diff options
151 files changed, 3671 insertions, 1267 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 2ce3fb05cc..df1ef297bf 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -24,6 +24,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp libs/nativewindow/ libs/renderengine/ libs/ui/ + libs/vibrator/ libs/vr/ opengl/libs/ services/bufferhub/ diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc index fa7be1816a..041ffe1c10 100644 --- a/cmds/atrace/atrace_userdebug.rc +++ b/cmds/atrace/atrace_userdebug.rc @@ -24,3 +24,7 @@ on post-fs chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/filter chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_exit/filter chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/filter + + # Allow traced_probes to use the kprobe interface + chmod 0666 /sys/kernel/debug/tracing/kprobe_events + chmod 0666 /sys/kernel/tracing/kprobe_events diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index c163095c50..77e732805e 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -18,6 +18,7 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#include <com_android_graphics_libgui_flags.h> #include <gui/SurfaceComposerClient.h> #include <ui/DisplayMode.h> @@ -202,6 +203,14 @@ bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) { bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, sp<GLConsumer>* glConsumer, EGLSurface* surface) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<GLConsumer> glc = new GLConsumer(name, GL_TEXTURE_EXTERNAL_OES, false, true); + glc->setDefaultBufferSize(w, h); + glc->getSurface()->setMaxDequeuedBufferCount(2); + glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); + + sp<ANativeWindow> anw = glc->getSurface(); +#else sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); @@ -212,6 +221,7 @@ bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); sp<ANativeWindow> anw = new Surface(producer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr); if (s == EGL_NO_SURFACE) { fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index ee91d80a3b..e89543e46f 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -1449,7 +1449,7 @@ TEST_F(ProfileTest, CopySystemProfileFailWrongProfileName) { class BootProfileTest : public ProfileTest { public: - std::vector<const std::string> extra_apps_; + std::vector<std::string> extra_apps_; std::vector<int64_t> extra_ce_data_inodes_; virtual void SetUp() { diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index 910cd630f3..19201b2c89 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -101,6 +101,9 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) { EXPECT_EQ(0, validate_apk_path(path2)) << path2 << " should be allowed as a valid path"; + const char* path3 = TEST_APP_DIR "..example..com../example.apk"; + EXPECT_EQ(0, validate_apk_path(path3)) << path3 << " should be allowed as a valid path"; + const char *badint1 = TEST_APP_DIR "../example.apk"; EXPECT_EQ(-1, validate_apk_path(badint1)) << badint1 << " should be rejected as a invalid path"; diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index ffc082d5b2..b05c655517 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -1040,25 +1040,30 @@ static int validate_path(const std::string& dir, const std::string& path, int ma LOG(ERROR) << "Invalid directory " << dir; return -1; } - if (path.find("..") != std::string::npos) { - LOG(ERROR) << "Invalid path " << path; - return -1; - } if (path.compare(0, dir.size(), dir) != 0) { // Common case, path isn't under directory return -1; } - // Count number of subdirectories - auto pos = path.find('/', dir.size()); + // Count number of subdirectories and invalidate ".." subdirectories + auto last = dir.size(); + auto pos = path.find('/', last); int count = 0; while (pos != std::string::npos) { - auto next = path.find('/', pos + 1); - if (next > pos + 1) { + if (pos > last + 1) { count++; } - pos = next; + if (path.substr(last, pos - last) == "..") { + LOG(ERROR) << "Invalid path " << path; + return -1; + } + last = pos + 1; + pos = path.find('/', last); + } + if (path.substr(last, path.size() - last) == "..") { + LOG(ERROR) << "Invalid path " << path; + return -1; } if (count > maxSubdirs) { diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h index 769670ea99..0b7e16bc7d 100644 --- a/include/audiomanager/IAudioManager.h +++ b/include/audiomanager/IAudioManager.h @@ -27,7 +27,7 @@ namespace android { // ---------------------------------------------------------------------------- - +// TODO(b/309532236) replace this class with AIDL generated parcelable class IAudioManager : public IInterface { public: @@ -43,6 +43,7 @@ public: RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 6, PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 7, PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 8, + PERMISSION_UPDATE_BARRIER = IBinder::FIRST_CALL_TRANSACTION + 9, }; DECLARE_META_INTERFACE(AudioManager) @@ -63,6 +64,7 @@ public: /*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0; /*oneway*/ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event, const std::unique_ptr<os::PersistableBundle>& extras) = 0; + virtual status_t permissionUpdateBarrier() = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index 43e9fac5e2..3d5d52e80c 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -234,7 +234,7 @@ class SmallVector final : details::ArrayTraits<T>, details::ArrayComparators<Sma } // Extracts the elements as std::vector. - std::vector<T> promote() && { + std::vector<std::remove_const_t<T>> promote() && { if (dynamic()) { return std::get<Dynamic>(std::move(vector_)).promote(); } else { @@ -290,11 +290,11 @@ template <typename T> class SmallVector<T, 0> final : details::ArrayTraits<T>, details::ArrayComparators<SmallVector>, details::ArrayIterators<SmallVector<T, 0>, T>, - std::vector<T> { + std::vector<std::remove_const_t<T>> { using details::ArrayTraits<T>::replace_at; using Iter = details::ArrayIterators<SmallVector, T>; - using Impl = std::vector<T>; + using Impl = std::vector<std::remove_const_t<T>>; friend Iter; @@ -394,12 +394,12 @@ class SmallVector<T, 0> final : details::ArrayTraits<T>, pop_back(); } - std::vector<T> promote() && { return std::move(*this); } + std::vector<std::remove_const_t<T>> promote() && { return std::move(*this); } private: template <typename U, std::size_t M> static Impl convert(SmallVector<U, M>&& other) { - if constexpr (std::is_constructible_v<Impl, std::vector<U>&&>) { + if constexpr (std::is_constructible_v<Impl, std::vector<std::remove_const_t<U>>&&>) { return std::move(other).promote(); } else { SmallVector vector(other.size()); diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h index 55e058332d..5bd5070488 100644 --- a/include/input/InputEventBuilders.h +++ b/include/input/InputEventBuilders.h @@ -19,6 +19,8 @@ #include <android/input.h> #include <attestation/HmacKeyManager.h> #include <input/Input.h> +#include <input/InputTransport.h> +#include <ui/LogicalDisplayId.h> #include <utils/Timers.h> // for nsecs_t, systemTime #include <vector> @@ -44,6 +46,11 @@ public: PointerBuilder& y(float y) { return axis(AMOTION_EVENT_AXIS_Y, y); } + PointerBuilder& isResampled(bool isResampled) { + mCoords.isResampled = isResampled; + return *this; + } + PointerBuilder& axis(int32_t axis, float value) { mCoords.setAxisValue(axis, value); return *this; @@ -58,6 +65,87 @@ private: PointerCoords mCoords; }; +class InputMessageBuilder { +public: + InputMessageBuilder(InputMessage::Type type, uint32_t seq) : mType{type}, mSeq{seq} {} + + InputMessageBuilder& eventId(int32_t eventId) { + mEventId = eventId; + return *this; + } + + InputMessageBuilder& eventTime(nsecs_t eventTime) { + mEventTime = eventTime; + return *this; + } + + InputMessageBuilder& deviceId(DeviceId deviceId) { + mDeviceId = deviceId; + return *this; + } + + InputMessageBuilder& source(int32_t source) { + mSource = source; + return *this; + } + + InputMessageBuilder& displayId(ui::LogicalDisplayId displayId) { + mDisplayId = displayId; + return *this; + } + + InputMessageBuilder& action(int32_t action) { + mAction = action; + return *this; + } + + InputMessageBuilder& downTime(nsecs_t downTime) { + mDownTime = downTime; + return *this; + } + + InputMessageBuilder& pointer(PointerBuilder pointerBuilder) { + mPointers.push_back(pointerBuilder); + return *this; + } + + InputMessage build() const { + InputMessage message{}; + // Header + message.header.type = mType; + message.header.seq = mSeq; + // Body + message.body.motion.eventId = mEventId; + message.body.motion.pointerCount = mPointers.size(); + message.body.motion.eventTime = mEventTime; + message.body.motion.deviceId = mDeviceId; + message.body.motion.source = mSource; + message.body.motion.displayId = mDisplayId.val(); + message.body.motion.action = mAction; + message.body.motion.downTime = mDownTime; + + for (size_t i = 0; i < mPointers.size(); ++i) { + message.body.motion.pointers[i].properties = mPointers[i].buildProperties(); + message.body.motion.pointers[i].coords = mPointers[i].buildCoords(); + } + return message; + } + +private: + const InputMessage::Type mType; + const uint32_t mSeq; + + int32_t mEventId{InputEvent::nextId()}; + nsecs_t mEventTime{systemTime(SYSTEM_TIME_MONOTONIC)}; + DeviceId mDeviceId{DEFAULT_DEVICE_ID}; + int32_t mSource{AINPUT_SOURCE_TOUCHSCREEN}; + ui::LogicalDisplayId mDisplayId{ui::LogicalDisplayId::DEFAULT}; + int32_t mAction{AMOTION_EVENT_ACTION_MOVE}; + nsecs_t mDownTime{mEventTime}; + + std::vector<PointerBuilder> mPointers; +}; + class MotionEventBuilder { public: MotionEventBuilder(int32_t action, int32_t source) { diff --git a/include/input/Resampler.h b/include/input/Resampler.h index ff9c4b0868..2892137ae7 100644 --- a/include/input/Resampler.h +++ b/include/input/Resampler.h @@ -18,6 +18,7 @@ #include <chrono> #include <optional> +#include <vector> #include <input/Input.h> #include <input/InputTransport.h> @@ -44,7 +45,7 @@ struct Resampler { * samples by the end of the resampling. No other field of motionEvent should be modified. * - If resampling does not occur, then motionEvent must not be modified in any way. */ - virtual void resampleMotionEvent(const std::chrono::nanoseconds resampleTime, + virtual void resampleMotionEvent(std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent, const InputMessage* futureSample) = 0; }; @@ -60,7 +61,7 @@ public: * data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and * `motionEvent` is unmodified. */ - void resampleMotionEvent(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent, + void resampleMotionEvent(std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent, const InputMessage* futureSample) override; private: @@ -71,11 +72,15 @@ private: struct Sample { std::chrono::nanoseconds eventTime; - Pointer pointer; + std::vector<Pointer> pointers; - Sample(const std::chrono::nanoseconds eventTime, const PointerProperties& properties, - const PointerCoords& coords) - : eventTime{eventTime}, pointer{properties, coords} {} + std::vector<PointerCoords> asPointerCoords() const { + std::vector<PointerCoords> pointersCoords; + for (const Pointer& pointer : pointers) { + pointersCoords.push_back(pointer.coords); + } + return pointersCoords; + } }; /** @@ -92,24 +97,50 @@ private: RingBuffer<Sample> mLatestSamples{/*capacity=*/2}; /** - * Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. (If + * Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. If * motionEvent has fewer samples than mLatestSamples.capacity(), then the available samples are - * added to mLatestSamples.) + * added to mLatestSamples. */ void updateLatestSamples(const MotionEvent& motionEvent); + static Sample messageToSample(const InputMessage& message); + + /** + * Checks if auxiliary sample has the same pointer properties of target sample. That is, + * auxiliary pointer IDs must appear in the same order as target pointer IDs, their toolType + * must match and be resampleable. + */ + static bool pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary); + /** - * May add a sample at the end of motionEvent with eventTime equal to resampleTime, and - * interpolated coordinates between the latest motionEvent sample and futureSample. + * Checks if there are necessary conditions to interpolate. For example, interpolation cannot + * take place if samples are too far apart in time. mLatestSamples must have at least one sample + * when canInterpolate is invoked. */ - void interpolate(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent, - const InputMessage& futureSample) const; + bool canInterpolate(const InputMessage& futureSample) const; /** - * May add a sample at the end of motionEvent by extrapolating from the latest two samples. The - * added sample either has eventTime equal to resampleTime, or an earlier time if resampleTime - * is too far in the future. + * Returns a sample interpolated between the latest sample of mLatestSamples and futureSample, + * if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt. + * mLatestSamples must have at least one sample when attemptInterpolation is called. */ - void extrapolate(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent) const; + std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime, + const InputMessage& futureSample) const; + + /** + * Checks if there are necessary conditions to extrapolate. That is, there are at least two + * samples in mLatestSamples, and delta is bounded within a time interval. + */ + bool canExtrapolate() const; + + /** + * Returns a sample extrapolated from the two samples of mLatestSamples, if the conditions from + * canExtrapolate are satisfied. The returned sample either has eventTime equal to resampleTime, + * or an earlier time if resampleTime is too far in the future. If canExtrapolate returns false, + * this function returns nullopt. + */ + std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const; + + inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent); }; -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index de331b79c2..379b609e9f 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -87,6 +87,11 @@ cc_library_headers { cc_cmake_snapshot { name: "binder_sdk", + dist: { + targets: ["binder_sdk"], + dest: "binder_sdk.zip", + }, + modules_host: [ "libbinder_sdk", "libbinder_sdk_single_threaded", diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h index f5d7e66568..8f3839fcb2 100644 --- a/libs/binder/BackendUnifiedServiceManager.h +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -57,8 +57,6 @@ public: return mTheRealServiceManager->getInterfaceDescriptor(); } - IBinder* onAsBinder() override { return IInterface::asBinder(mTheRealServiceManager).get(); } - private: sp<os::IServiceManager> mTheRealServiceManager; void toBinderService(const os::Service& in, os::Service* _out); diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 333f956556..c55dd9de1b 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -79,10 +79,9 @@ IServiceManager::IServiceManager() {} IServiceManager::~IServiceManager() {} // From the old libbinder IServiceManager interface to IServiceManager. -class ServiceManagerShim : public IServiceManager -{ +class CppBackendShim : public IServiceManager { public: - explicit ServiceManagerShim (const sp<AidlServiceManager>& impl); + explicit CppBackendShim(const sp<BackendUnifiedServiceManager>& impl); sp<IBinder> getService(const String16& name) const override; sp<IBinder> checkService(const String16& name) const override; @@ -136,11 +135,11 @@ protected: sp<RegistrationWaiter>* waiter); // Directly get the service in a way that, for lazy services, requests the service to be started - // if it is not currently started. This way, calls directly to ServiceManagerShim::getService + // if it is not currently started. This way, calls directly to CppBackendShim::getService // will still have the 5s delay that is expected by a large amount of Android code. // - // When implementing ServiceManagerShim, use realGetService instead of - // mUnifiedServiceManager->getService so that it can be overridden in ServiceManagerHostShim. + // When implementing CppBackendShim, use realGetService instead of + // mUnifiedServiceManager->getService so that it can be overridden in CppServiceManagerHostShim. virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) { Service service; Status status = mUnifiedServiceManager->getService2(name, &service); @@ -155,7 +154,7 @@ protected: sp<IServiceManager> defaultServiceManager() { std::call_once(gSmOnce, []() { - gDefaultServiceManager = sp<ServiceManagerShim>::make(getBackendUnifiedServiceManager()); + gDefaultServiceManager = sp<CppBackendShim>::make(getBackendUnifiedServiceManager()); }); return gDefaultServiceManager; @@ -279,16 +278,14 @@ void* openDeclaredPassthroughHal(const String16& interface, const String16& inst // ---------------------------------------------------------------------- -ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl) { - mUnifiedServiceManager = sp<BackendUnifiedServiceManager>::make(impl); -} +CppBackendShim::CppBackendShim(const sp<BackendUnifiedServiceManager>& impl) + : mUnifiedServiceManager(impl) {} // This implementation could be simplified and made more efficient by delegating // to waitForService. However, this changes the threading structure in some // cases and could potentially break prebuilts. Once we have higher logistical // complexity, this could be attempted. -sp<IBinder> ServiceManagerShim::getService(const String16& name) const -{ +sp<IBinder> CppBackendShim::getService(const String16& name) const { static bool gSystemBootCompleted = false; sp<IBinder> svc = checkService(name); @@ -332,8 +329,7 @@ sp<IBinder> ServiceManagerShim::getService(const String16& name) const return nullptr; } -sp<IBinder> ServiceManagerShim::checkService(const String16& name) const -{ +sp<IBinder> CppBackendShim::checkService(const String16& name) const { Service ret; if (!mUnifiedServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { return nullptr; @@ -341,16 +337,14 @@ sp<IBinder> ServiceManagerShim::checkService(const String16& name) const return ret.get<Service::Tag::binder>(); } -status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated, int dumpsysPriority) -{ +status_t CppBackendShim::addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated, int dumpsysPriority) { Status status = mUnifiedServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority); return status.exceptionCode(); } -Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority) -{ +Vector<String16> CppBackendShim::listServices(int dumpsysPriority) { std::vector<std::string> ret; if (!mUnifiedServiceManager->listServices(dumpsysPriority, &ret).isOk()) { return {}; @@ -364,8 +358,7 @@ Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority) return res; } -sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) -{ +sp<IBinder> CppBackendShim::waitForService(const String16& name16) { class Waiter : public android::os::BnServiceCallback { Status onRegistration(const std::string& /*name*/, const sp<IBinder>& binder) override { @@ -454,7 +447,7 @@ sp<IBinder> ServiceManagerShim::waitForService(const String16& name16) } } -bool ServiceManagerShim::isDeclared(const String16& name) { +bool CppBackendShim::isDeclared(const String16& name) { bool declared; if (Status status = mUnifiedServiceManager->isDeclared(String8(name).c_str(), &declared); !status.isOk()) { @@ -465,7 +458,7 @@ bool ServiceManagerShim::isDeclared(const String16& name) { return declared; } -Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interface) { +Vector<String16> CppBackendShim::getDeclaredInstances(const String16& interface) { std::vector<std::string> out; if (Status status = mUnifiedServiceManager->getDeclaredInstances(String8(interface).c_str(), &out); @@ -483,7 +476,7 @@ Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interf return res; } -std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) { +std::optional<String16> CppBackendShim::updatableViaApex(const String16& name) { std::optional<std::string> declared; if (Status status = mUnifiedServiceManager->updatableViaApex(String8(name).c_str(), &declared); !status.isOk()) { @@ -494,7 +487,7 @@ std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& nam return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt; } -Vector<String16> ServiceManagerShim::getUpdatableNames(const String16& apexName) { +Vector<String16> CppBackendShim::getUpdatableNames(const String16& apexName) { std::vector<std::string> out; if (Status status = mUnifiedServiceManager->getUpdatableNames(String8(apexName).c_str(), &out); !status.isOk()) { @@ -511,7 +504,7 @@ Vector<String16> ServiceManagerShim::getUpdatableNames(const String16& apexName) return res; } -std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnectionInfo( +std::optional<IServiceManager::ConnectionInfo> CppBackendShim::getConnectionInfo( const String16& name) { std::optional<os::ConnectionInfo> connectionInfo; if (Status status = @@ -526,8 +519,8 @@ std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnection : std::nullopt; } -status_t ServiceManagerShim::registerForNotifications(const String16& name, - const sp<AidlRegistrationCallback>& cb) { +status_t CppBackendShim::registerForNotifications(const String16& name, + const sp<AidlRegistrationCallback>& cb) { if (cb == nullptr) { ALOGE("%s: null cb passed", __FUNCTION__); return BAD_VALUE; @@ -546,9 +539,9 @@ status_t ServiceManagerShim::registerForNotifications(const String16& name, return OK; } -void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb, - ServiceCallbackMap::iterator* it, - sp<RegistrationWaiter>* waiter) { +void CppBackendShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb, + ServiceCallbackMap::iterator* it, + sp<RegistrationWaiter>* waiter) { std::vector<LocalRegistrationAndWaiter>& localRegistrationAndWaiters = (*it)->second; for (auto lit = localRegistrationAndWaiters.begin(); lit != localRegistrationAndWaiters.end();) { @@ -567,8 +560,8 @@ void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrat } } -status_t ServiceManagerShim::unregisterForNotifications(const String16& name, - const sp<AidlRegistrationCallback>& cb) { +status_t CppBackendShim::unregisterForNotifications(const String16& name, + const sp<AidlRegistrationCallback>& cb) { if (cb == nullptr) { ALOGE("%s: null cb passed", __FUNCTION__); return BAD_VALUE; @@ -597,7 +590,7 @@ status_t ServiceManagerShim::unregisterForNotifications(const String16& name, return OK; } -std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDebugInfo() { +std::vector<IServiceManager::ServiceDebugInfo> CppBackendShim::getServiceDebugInfo() { std::vector<os::ServiceDebugInfo> serviceDebugInfos; std::vector<IServiceManager::ServiceDebugInfo> ret; if (Status status = mUnifiedServiceManager->getServiceDebugInfo(&serviceDebugInfos); @@ -615,21 +608,21 @@ std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDeb } #ifndef __ANDROID__ -// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API. +// CppBackendShim for host. Implements the old libbinder android::IServiceManager API. // The internal implementation of the AIDL interface android::os::IServiceManager calls into // on-device service manager. -class ServiceManagerHostShim : public ServiceManagerShim { +class CppServiceManagerHostShim : public CppBackendShim { public: - ServiceManagerHostShim(const sp<AidlServiceManager>& impl, - const RpcDelegateServiceManagerOptions& options) - : ServiceManagerShim(impl), mOptions(options) {} - // ServiceManagerShim::getService is based on checkService, so no need to override it. + CppServiceManagerHostShim(const sp<AidlServiceManager>& impl, + const RpcDelegateServiceManagerOptions& options) + : CppBackendShim(sp<BackendUnifiedServiceManager>::make(impl)), mOptions(options) {} + // CppBackendShim::getService is based on checkService, so no need to override it. sp<IBinder> checkService(const String16& name) const override { return getDeviceService({String8(name).c_str()}, mOptions); } protected: - // Override realGetService for ServiceManagerShim::waitForService. + // Override realGetService for CppBackendShim::waitForService. Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) override { *_aidl_return = getDeviceService({"-g", name}, mOptions); return Status::ok(); @@ -650,7 +643,7 @@ sp<IServiceManager> createRpcDelegateServiceManager( ALOGE("getDeviceService(\"manager\") returns non service manager"); return nullptr; } - return sp<ServiceManagerHostShim>::make(interface, options); + return sp<CppServiceManagerHostShim>::make(interface, options); } #endif diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 2929bce897..72d255e816 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -771,7 +771,7 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUC * This provides a per-process-unique total ordering of binders where a null * AIBinder* object is considered to be before all other binder objects. * For instance, two binders refer to the same object in a local or remote - * process when both AIBinder_lt(a, b) and AIBinder(b, a) are false. This API + * process when both AIBinder_lt(a, b) and AIBinder_lt(b, a) are false. This API * might be used to insert and lookup binders in binary search trees. * * AIBinder* pointers themselves actually also create a per-process-unique total diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h index 68528e1004..6aff994a15 100644 --- a/libs/binder/ndk/include_platform/android/binder_process.h +++ b/libs/binder/ndk/include_platform/android/binder_process.h @@ -47,8 +47,11 @@ void ABinderProcess_startThreadPool(void); * be called once before startThreadPool. The number of threads can never decrease. * * This count refers to the number of threads that will be created lazily by the kernel, in - * addition to the threads created by ABinderProcess_startThreadPool or - * ABinderProcess_joinThreadPool. + * addition to the single threads created by ABinderProcess_startThreadPool (+1) or + * ABinderProcess_joinThreadPool (+1). Note: ABinderProcess_startThreadPool starts a thread + * itself, but it also enables up to the number of threads passed to this function to start. + * This function does not start any threads itself; it only configures + * ABinderProcess_startThreadPool. * * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main * function should be responsible for configuring the threadpool for the entire application. @@ -63,8 +66,8 @@ bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads); bool ABinderProcess_isThreadPoolStarted(void); /** * This adds the current thread to the threadpool. This thread will be in addition to the thread - * started by ABinderProcess_startThreadPool and the lazy kernel-started threads specified by - * ABinderProcess_setThreadPoolMaxThreadCount. + * configured with ABinderProcess_setThreadPoolMaxThreadCount and started with + * ABinderProcess_startThreadPool. * * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main * function should be responsible for configuring the threadpool for the entire application. diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp index 2e463451f9..174fe8aba8 100644 --- a/libs/binder/rust/rpcbinder/Android.bp +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -32,6 +32,7 @@ rust_library { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.microfuchsia", "com.android.uwb", "com.android.virt", ], @@ -60,6 +61,7 @@ rust_library { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.microfuchsia", "com.android.uwb", "com.android.virt", ], @@ -93,6 +95,7 @@ rust_bindgen { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.microfuchsia", "com.android.uwb", "com.android.virt", ], diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 21c32acb0a..957871379b 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -46,7 +46,7 @@ cc_test { "libbinder", ], test_suites: [ - "device-tests", + "general-tests", "vts", ], } @@ -137,7 +137,7 @@ cc_test { "libgmock", ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -705,7 +705,7 @@ cc_test { "libutils", ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -762,7 +762,7 @@ cc_test { ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index 2cec243c38..c6fd4870a0 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -301,7 +301,8 @@ TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) { auto proc = createRpcTestSocketServerProcess({}); - sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager()); + sp<IBinder> someRealBinder = defaultServiceManager()->getService(String16("activity")); + ASSERT_NE(someRealBinder, nullptr); sp<IBinder> outBinder; EXPECT_EQ(INVALID_OPERATION, proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError()); diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index fe44ea5e28..583ad015e1 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -42,7 +42,7 @@ public: // equivalent. struct PortAcl { uint32_t flags; - std::vector<const uuid> uuids; + std::vector<uuid> uuids; const void* extraData; }; diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs index 17d4d8767f..9c48b49812 100644 --- a/libs/bufferstreams/rust/src/lib.rs +++ b/libs/bufferstreams/rust/src/lib.rs @@ -37,23 +37,23 @@ pub extern "C" fn hello() -> bool { /// BufferPublishers are required to adhere to the following, based on the /// reactive streams specification: /// * The total number of on_next´s signalled by a Publisher to a Subscriber -/// MUST be less than or equal to the total number of elements requested by that -/// Subscriber´s Subscription at all times. +/// MUST be less than or equal to the total number of elements requested by that +/// Subscriber´s Subscription at all times. /// * A Publisher MAY signal fewer on_next than requested and terminate the -/// Subscription by calling on_complete or on_error. +/// Subscription by calling on_complete or on_error. /// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber -/// MUST be signaled serially. +/// MUST be signaled serially. /// * If a Publisher fails it MUST signal an on_error. /// * If a Publisher terminates successfully (finite stream) it MUST signal an -/// on_complete. +/// on_complete. /// * If a Publisher signals either on_error or on_complete on a Subscriber, -/// that Subscriber’s Subscription MUST be considered cancelled. +/// that Subscriber’s Subscription MUST be considered cancelled. /// * Once a terminal state has been signaled (on_error, on_complete) it is -/// REQUIRED that no further signals occur. +/// REQUIRED that no further signals occur. /// * If a Subscription is cancelled its Subscriber MUST eventually stop being -/// signaled. +/// signaled. /// * A Publisher MAY support multiple Subscribers and decides whether each -/// Subscription is unicast or multicast. +/// Subscription is unicast or multicast. pub trait BufferPublisher { /// Returns the StreamConfig of buffers that publisher creates. fn get_publisher_stream_config(&self) -> StreamConfig; @@ -69,25 +69,25 @@ pub trait BufferPublisher { /// BufferSubcribers are required to adhere to the following, based on the /// reactive streams specification: /// * The total number of on_next´s signalled by a Publisher to a Subscriber -/// MUST be less than or equal to the total number of elements requested by that -/// Subscriber´s Subscription at all times. +/// MUST be less than or equal to the total number of elements requested by that +/// Subscriber´s Subscription at all times. /// * A Publisher MAY signal fewer on_next than requested and terminate the -/// Subscription by calling on_complete or on_error. +/// Subscription by calling on_complete or on_error. /// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber -/// MUST be signaled serially. +/// MUST be signaled serially. /// * If a Publisher fails it MUST signal an on_error. /// * If a Publisher terminates successfully (finite stream) it MUST signal an -/// on_complete. +/// on_complete. /// * If a Publisher signals either on_error or on_complete on a Subscriber, -/// that Subscriber’s Subscription MUST be considered cancelled. +/// that Subscriber’s Subscription MUST be considered cancelled. /// * Once a terminal state has been signaled (on_error, on_complete) it is -/// REQUIRED that no further signals occur. +/// REQUIRED that no further signals occur. /// * If a Subscription is cancelled its Subscriber MUST eventually stop being -/// signaled. +/// signaled. /// * Publisher.subscribe MAY be called as many times as wanted but MUST be -/// with a different Subscriber each time. +/// with a different Subscriber each time. /// * A Publisher MAY support multiple Subscribers and decides whether each -/// Subscription is unicast or multicast. +/// Subscription is unicast or multicast. pub trait BufferSubscriber { /// The StreamConfig of buffers that this subscriber expects. fn get_subscriber_stream_config(&self) -> StreamConfig; @@ -111,39 +111,39 @@ pub trait BufferSubscriber { /// BufferSubcriptions are required to adhere to the following, based on the /// reactive streams specification: /// * Subscription.request and Subscription.cancel MUST only be called inside -/// of its Subscriber context. +/// of its Subscriber context. /// * The Subscription MUST allow the Subscriber to call Subscription.request -/// synchronously from within on_next or on_subscribe. +/// synchronously from within on_next or on_subscribe. /// * Subscription.request MUST place an upper bound on possible synchronous -/// recursion between Publisher and Subscriber. +/// recursion between Publisher and Subscriber. /// * Subscription.request SHOULD respect the responsivity of its caller by -/// returning in a timely manner. +/// returning in a timely manner. /// * Subscription.cancel MUST respect the responsivity of its caller by -/// returning in a timely manner, MUST be idempotent and MUST be thread-safe. +/// returning in a timely manner, MUST be idempotent and MUST be thread-safe. /// * After the Subscription is cancelled, additional -/// Subscription.request(n: u64) MUST be NOPs. +/// Subscription.request(n: u64) MUST be NOPs. /// * After the Subscription is cancelled, additional Subscription.cancel() -/// MUST be NOPs. +/// MUST be NOPs. /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MUST register the given number of additional elements to be produced to the -/// respective subscriber. +/// MUST register the given number of additional elements to be produced to the +/// respective subscriber. /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MUST signal on_error if the argument is <= 0. The cause message SHOULD -/// explain that non-positive request signals are illegal. +/// MUST signal on_error if the argument is <= 0. The cause message SHOULD +/// explain that non-positive request signals are illegal. /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MAY synchronously call on_next on this (or other) subscriber(s). +/// MAY synchronously call on_next on this (or other) subscriber(s). /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MAY synchronously call on_complete or on_error on this (or other) -/// subscriber(s). +/// MAY synchronously call on_complete or on_error on this (or other) +/// subscriber(s). /// * While the Subscription is not cancelled, Subscription.cancel() MUST -/// request the Publisher to eventually stop signaling its Subscriber. The -/// operation is NOT REQUIRED to affect the Subscription immediately. +/// request the Publisher to eventually stop signaling its Subscriber. The +/// operation is NOT REQUIRED to affect the Subscription immediately. /// * While the Subscription is not cancelled, Subscription.cancel() MUST -/// request the Publisher to eventually drop any references to the corresponding -/// subscriber. +/// request the Publisher to eventually drop any references to the corresponding +/// subscriber. /// * While the Subscription is not cancelled, calling Subscription.cancel MAY -/// cause the Publisher, if stateful, to transition into the shut-down state if -/// no other Subscription exists at this point. +/// cause the Publisher, if stateful, to transition into the shut-down state if +/// no other Subscription exists at this point. /// * Calling Subscription.cancel MUST return normally. /// * Calling Subscription.request MUST return normally. pub trait BufferSubscription: Send + Sync + 'static { diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp index 833718213a..d9cdb59dfe 100644 --- a/libs/gralloc/types/fuzzer/Android.bp +++ b/libs/gralloc/types/fuzzer/Android.bp @@ -28,14 +28,10 @@ cc_fuzz { ], static_libs: [ "libbase", - "libcgrouprc", - "libcgrouprc_format", "libcutils", "libgralloctypes", "libhidlbase", "liblog", - "libprocessgroup", - "libjsoncpp", "libutils", ], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 52383acb34..d1a56635f5 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -83,6 +83,55 @@ static constexpr const char* kNativeLibrariesSystemConfigPath[] = static const char* kLlndkLibrariesTxtPath = "/system/etc/llndk.libraries.txt"; +// List of libraries that were previously available via VNDK-SP, +// and are now available via SPHAL. +// On modern devices that lack the VNDK APEX, the device no longer +// contains a helpful list of these libraries on the filesystem as above. +// See system/sepolicy/vendor/file_contexts +static const char* kFormerlyVndkspLibrariesList = + "android.hardware.common-V2-ndk.so:" + "android.hardware.common.fmq-V1-ndk.so:" + "android.hardware.graphics.allocator-V2-ndk.so:" + "android.hardware.graphics.common-V5-ndk.so:" + "android.hardware.graphics.common@1.0.so:" + "android.hardware.graphics.common@1.1.so:" + "android.hardware.graphics.common@1.2.so:" + "android.hardware.graphics.composer3-V1-ndk.so:" + "android.hardware.graphics.mapper@2.0.so:" + "android.hardware.graphics.mapper@2.1.so:" + "android.hardware.graphics.mapper@3.0.so:" + "android.hardware.graphics.mapper@4.0.so:" + "android.hardware.renderscript@1.0.so:" + "android.hidl.memory.token@1.0.so:" + "android.hidl.memory@1.0-impl.so:" + "android.hidl.memory@1.0.so:" + "android.hidl.safe_union@1.0.so:" + "libRSCpuRef.so:" + "libRSDriver.so:" + "libRS_internal.so:" + "libbacktrace.so:" + "libbase.so:" + "libbcinfo.so:" + "libblas.so:" + "libc++.so:" + "libcompiler_rt.so:" + "libcutils.so:" + "libdmabufheap.so:" + "libft2.so:" + "libgralloctypes.so:" + "libhardware.so:" + "libhidlbase.so:" + "libhidlmemory.so:" + "libion.so:" + "libjsoncpp.so:" + "liblzma.so:" + "libpng.so:" + "libprocessgroup.so:" + "libunwindstack.so:" + "libutils.so:" + "libutilscallstack.so:" + "libz.so"; + static std::string vndkVersionStr() { #ifdef __BIONIC__ return base::GetProperty("ro.vndk.version", ""); @@ -122,8 +171,12 @@ static bool readConfig(const std::string& configFile, std::vector<std::string>* static const std::string getSystemNativeLibraries(NativeLibrary type) { std::string nativeLibrariesSystemConfig = ""; - if (!isVndkEnabled() && type == NativeLibrary::LLNDK) { - nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath; + if (!isVndkEnabled()) { + if (type == NativeLibrary::VNDKSP) { + return kFormerlyVndkspLibrariesList; + } else { + nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath; + } } else { nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type]; insertVndkVersionStr(&nativeLibrariesSystemConfig); @@ -263,7 +316,7 @@ android_namespace_t* GraphicsEnv::getDriverNamespace() { ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str()); } - auto vndkNamespace = android_get_exported_namespace("vndk"); + auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal"); if (!vndkNamespace) { mDriverNamespace = nullptr; return mDriverNamespace; @@ -348,18 +401,10 @@ void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { switch (driver) { case GpuStatsInfo::Driver::GL: case GpuStatsInfo::Driver::GL_UPDATED: - case GpuStatsInfo::Driver::ANGLE: { - if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE || - mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) { - mGpuStats.glDriverToLoad = driver; - break; - } - - if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) { - mGpuStats.glDriverFallback = driver; - } + case GpuStatsInfo::Driver::ANGLE: + mGpuStats.glDriverToLoad = driver; break; - } + case GpuStatsInfo::Driver::VULKAN: case GpuStatsInfo::Driver::VULKAN_UPDATED: { if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE || @@ -508,8 +553,7 @@ void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, bool isIntendedDriverLoaded = false; if (api == GpuStatsInfo::Api::API_GL) { driver = mGpuStats.glDriverToLoad; - isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE); + isIntendedDriverLoaded = isDriverLoaded; } else { driver = mGpuStats.vkDriverToLoad; isIntendedDriverLoaded = @@ -631,7 +675,7 @@ android_namespace_t* GraphicsEnv::getAngleNamespace() { return mAngleNamespace; } - auto vndkNamespace = android_get_exported_namespace("vndk"); + auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal"); if (!vndkNamespace) { mAngleNamespace = nullptr; return mAngleNamespace; diff --git a/libs/graphicsenv/OWNERS b/libs/graphicsenv/OWNERS index 1db8cbe52f..4aa8fff1e2 100644 --- a/libs/graphicsenv/OWNERS +++ b/libs/graphicsenv/OWNERS @@ -1,4 +1,11 @@ chrisforbes@google.com -cnorthrop@google.com ianelliott@google.com -lpy@google.com + +abdolrashidi@google.com +cclao@google.com +cnorthrop@google.com +hibrian@google.com +mathias@google.com +romanl@google.com +solti@google.com +yuxinhu@google.com diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index 7f45581da9..72f29c6b0b 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -141,7 +141,6 @@ public: std::string appPackageName = ""; int32_t vulkanVersion = 0; Driver glDriverToLoad = Driver::NONE; - Driver glDriverFallback = Driver::NONE; Driver vkDriverToLoad = Driver::NONE; Driver vkDriverFallback = Driver::NONE; bool glDriverToSend = false; diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index cda49850f2..8f6dd840aa 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -22,11 +22,14 @@ #include <com_android_graphics_libgui_flags.h> #include <cutils/atomic.h> +#include <ftl/fake_guard.h> #include <gui/BLASTBufferQueue.h> #include <gui/BufferItemConsumer.h> #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> +#include <sys/epoll.h> +#include <sys/eventfd.h> #include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> @@ -74,6 +77,12 @@ namespace android { std::unique_lock _lock{mutex}; \ base::ScopedLockAssertion assumeLocked(mutex); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) +static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK = + [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/, + std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {}; +#endif + void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; @@ -215,6 +224,12 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati }, this); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer; + gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer); + mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer)); +#endif + BQA_LOGV("BLASTBufferQueue created"); } @@ -244,6 +259,9 @@ BLASTBufferQueue::~BLASTBufferQueue() { void BLASTBufferQueue::onFirstRef() { // safe default, most producers are expected to override this mProducer->setMaxDequeuedBufferCount(2); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this)); +#endif } void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, @@ -269,6 +287,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, if (surfaceControlChanged) { t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer); +#endif applyTransaction = true; } mTransformHint = mSurfaceControl->getTransformHint(); @@ -306,14 +327,12 @@ static std::optional<SurfaceControlStats> findMatchingStat( return std::nullopt; } -static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime, - const sp<Fence>& presentFence, - const std::vector<SurfaceControlStats>& stats) { - if (context == nullptr) { - return; - } - sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context); - bq->transactionCommittedCallback(latchTime, presentFence, stats); +TransactionCompletedCallbackTakesContext BLASTBufferQueue::makeTransactionCommittedCallbackThunk() { + return [bbq = sp<BLASTBufferQueue>::fromExisting( + this)](void* /*context*/, nsecs_t latchTime, const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& stats) { + bbq->transactionCommittedCallback(latchTime, presentFence, stats); + }; } void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, @@ -346,18 +365,15 @@ void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " "empty."); } - decStrong((void*)transactionCommittedCallbackThunk); } } -static void transactionCallbackThunk(void* context, nsecs_t latchTime, - const sp<Fence>& presentFence, - const std::vector<SurfaceControlStats>& stats) { - if (context == nullptr) { - return; - } - sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context); - bq->transactionCallback(latchTime, presentFence, stats); +TransactionCompletedCallbackTakesContext BLASTBufferQueue::makeTransactionCallbackThunk() { + return [bbq = sp<BLASTBufferQueue>::fromExisting( + this)](void* /*context*/, nsecs_t latchTime, const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& stats) { + bbq->transactionCallback(latchTime, presentFence, stats); + }; } void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/, @@ -391,6 +407,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.latchTime, stat.frameEventStats.dequeueReadyTime); } +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) auto currFrameNumber = stat.frameEventStats.frameNumber; std::vector<ReleaseCallbackId> staleReleases; for (const auto& [key, value]: mSubmitted) { @@ -406,6 +423,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence stat.currentMaxAcquiredBufferCount, true /* fakeRelease */); } +#endif } else { BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback"); } @@ -413,23 +431,6 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " "empty."); } - - decStrong((void*)transactionCallbackThunk); - } -} - -// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the -// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client. -// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer. -// Otherwise, this is a no-op. -static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id, - const sp<Fence>& releaseFence, - std::optional<uint32_t> currentMaxAcquiredBufferCount) { - sp<BLASTBufferQueue> blastBufferQueue = context.promote(); - if (blastBufferQueue) { - blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount); - } else { - ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); } } @@ -442,6 +443,23 @@ void BLASTBufferQueue::flushShadowQueue() { } } +// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the +// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client. +// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer. +// Otherwise, this is a no-op. +ReleaseBufferCallback BLASTBufferQueue::makeReleaseBufferCallbackThunk() { + return [weakBbq = wp<BLASTBufferQueue>::fromExisting( + this)](const ReleaseCallbackId& id, const sp<Fence>& releaseFence, + std::optional<uint32_t> currentMaxAcquiredBufferCount) { + sp<BLASTBufferQueue> bbq = weakBbq.promote(); + if (!bbq) { + ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); + return; + } + bbq->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount); + }; +} + void BLASTBufferQueue::releaseBufferCallback( const ReleaseCallbackId& id, const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount) { @@ -510,7 +528,7 @@ void BLASTBufferQueue::releaseBuffer(const ReleaseCallbackId& callbackId, return; } #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) - if (!it->second.mIsStale) { + if (!it->second.disconnectedAfterAcquired) { mNumAcquired--; } #else @@ -566,7 +584,7 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( applyTransaction = false; } - BufferItem bufferItem; + BLASTBufferItem bufferItem; status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); @@ -610,9 +628,6 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( t->notifyProducerDisconnect(mSurfaceControl); } - // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. - incStrong((void*)transactionCallbackThunk); - // Only update mSize for destination bounds if the incoming buffer matches the requested size. // Otherwise, it could cause stretching since the destination bounds will update before the // buffer with the new size is acquired. @@ -625,9 +640,12 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, bufferItem.mScalingMode, crop); - auto releaseBufferCallback = - std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + ReleaseBufferCallback releaseBufferCallback = + applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk(); +#else + auto releaseBufferCallback = makeReleaseBufferCallbackThunk(); +#endif sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; nsecs_t dequeueTime = -1; @@ -645,7 +663,7 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); - t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this)); + t->addTransactionCompletedCallback(makeTransactionCallbackThunk(), nullptr); mSurfaceControlsWithPendingCallback.push(mSurfaceControl); @@ -805,9 +823,9 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { // Only need a commit callback when syncing to ensure the buffer that's synced has been // sent to SF - incStrong((void*)transactionCommittedCallbackThunk); - mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk, - static_cast<void*>(this)); + mSyncTransaction + ->addTransactionCommittedCallback(makeTransactionCommittedCallbackThunk(), + nullptr); if (mAcquireSingleBuffer) { prevCallback = mTransactionReadyCallback; prevTransaction = mSyncTransaction; @@ -1130,9 +1148,9 @@ public: // can be non-blocking when the producer is in the client process. class BBQBufferQueueProducer : public BufferQueueProducer { public: - BBQBufferQueueProducer(const sp<BufferQueueCore>& core, wp<BLASTBufferQueue> bbq) + BBQBufferQueueProducer(const sp<BufferQueueCore>& core, const wp<BLASTBufferQueue>& bbq) : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/), - mBLASTBufferQueue(std::move(bbq)) {} + mBLASTBufferQueue(bbq) {} status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) override { @@ -1156,10 +1174,19 @@ public: return status; } + // We need to reset dequeued and acquired counts because BufferQueueProducer::disconnect + // calls BufferQueueCore::freeAllBuffersLocked which frees all dequeued and acquired + // buffers. We don't reset mNumFrameAvailable because these buffers are still available + // in BufferItemConsumer. bbq->mNumDequeued = 0; bbq->mNumAcquired = 0; + // SurfaceFlinger sends release callbacks for buffers that have been acquired after a + // disconnect. We set disconnectedAfterAcquired to true so that we can ignore any stale + // releases that come in after the producer is disconnected. Otherwise, releaseBuffer will + // decrement mNumAcquired for a buffer that was acquired before we reset mNumAcquired to + // zero. for (auto& [releaseId, bufferItem] : bbq->mSubmitted) { - bufferItem.mIsStale = true; + bufferItem.disconnectedAfterAcquired = true; } return OK; @@ -1360,7 +1387,120 @@ bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceCon void BLASTBufferQueue::setTransactionHangCallback( std::function<void(const std::string&)> callback) { std::lock_guard _lock{mMutex}; - mTransactionHangCallback = callback; + mTransactionHangCallback = std::move(callback); +} + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + +BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( + std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint) + : mEndpoint{std::move(endpoint)} { + mEpollFd = android::base::unique_fd{epoll_create1(0)}; + LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(), + "Failed to create buffer release epoll file descriptor. errno=%d " + "message='%s'", + errno, strerror(errno)); + + epoll_event registerEndpointFd{}; + registerEndpointFd.events = EPOLLIN; + registerEndpointFd.data.fd = mEndpoint->getFd(); + status_t status = + epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd); + LOG_ALWAYS_FATAL_IF(status == -1, + "Failed to register buffer release consumer file descriptor with epoll. " + "errno=%d message='%s'", + errno, strerror(errno)); + + mEventFd = android::base::unique_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + LOG_ALWAYS_FATAL_IF(!mEventFd.ok(), + "Failed to create buffer release event file descriptor. errno=%d " + "message='%s'", + errno, strerror(errno)); + + epoll_event registerEventFd{}; + registerEventFd.events = EPOLLIN; + registerEventFd.data.fd = mEventFd.get(); + status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEventFd.get(), ®isterEventFd); + LOG_ALWAYS_FATAL_IF(status == -1, + "Failed to register buffer release event file descriptor with epoll. " + "errno=%d message='%s'", + errno, strerror(errno)); +} + +BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=( + BufferReleaseReader&& other) { + if (this != &other) { + ftl::FakeGuard guard{mMutex}; + ftl::FakeGuard otherGuard{other.mMutex}; + mEndpoint = std::move(other.mEndpoint); + mEpollFd = std::move(other.mEpollFd); + mEventFd = std::move(other.mEventFd); + } + return *this; +} + +status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, + sp<Fence>& outFence, + uint32_t& outMaxAcquiredBufferCount) { + epoll_event event{}; + while (true) { + int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */); + if (eventCount == 1) { + break; + } + if (eventCount == -1 && errno != EINTR) { + ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno, + strerror(errno)); + } + } + + if (event.data.fd == mEventFd.get()) { + uint64_t value; + if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) { + ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, + strerror(errno)); + } + return WOULD_BLOCK; + } + + std::lock_guard lock{mMutex}; + return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); } +void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() { + uint64_t value = 1; + if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) { + ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno)); + } +} + +void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) { + mRunning = std::make_shared<std::atomic_bool>(true); + mReader = bbq->mBufferReleaseReader; + std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() { + pthread_setname_np(pthread_self(), "BufferReleaseThread"); + while (*running) { + ReleaseCallbackId id; + sp<Fence> fence; + uint32_t maxAcquiredBufferCount; + if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount); + status != OK) { + continue; + } + sp<BLASTBufferQueue> bbq = weakBbq.promote(); + if (!bbq) { + return; + } + bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); + } + }).detach(); +} + +BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() { + *mRunning = false; + mReader->interruptBlockingRead(); +} + +#endif + } // namespace android diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 0714fd9501..b10996951b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -892,88 +892,6 @@ status_t InputWindowCommands::read(const Parcel& input) { // ---------------------------------------------------------------------------- -namespace gui { - -status_t CaptureArgs::writeToParcel(Parcel* output) const { - SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(pixelFormat)); - SAFE_PARCEL(output->write, sourceCrop); - SAFE_PARCEL(output->writeFloat, frameScaleX); - SAFE_PARCEL(output->writeFloat, frameScaleY); - SAFE_PARCEL(output->writeBool, captureSecureLayers); - SAFE_PARCEL(output->writeInt32, uid); - SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(dataspace)); - SAFE_PARCEL(output->writeBool, allowProtected); - SAFE_PARCEL(output->writeBool, grayscale); - SAFE_PARCEL(output->writeInt32, excludeHandles.size()); - for (auto& excludeHandle : excludeHandles) { - SAFE_PARCEL(output->writeStrongBinder, excludeHandle); - } - SAFE_PARCEL(output->writeBool, hintForSeamlessTransition); - return NO_ERROR; -} - -status_t CaptureArgs::readFromParcel(const Parcel* input) { - int32_t value = 0; - SAFE_PARCEL(input->readInt32, &value); - pixelFormat = static_cast<ui::PixelFormat>(value); - SAFE_PARCEL(input->read, sourceCrop); - SAFE_PARCEL(input->readFloat, &frameScaleX); - SAFE_PARCEL(input->readFloat, &frameScaleY); - SAFE_PARCEL(input->readBool, &captureSecureLayers); - SAFE_PARCEL(input->readInt32, &uid); - SAFE_PARCEL(input->readInt32, &value); - dataspace = static_cast<ui::Dataspace>(value); - SAFE_PARCEL(input->readBool, &allowProtected); - SAFE_PARCEL(input->readBool, &grayscale); - int32_t numExcludeHandles = 0; - SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize()); - excludeHandles.reserve(numExcludeHandles); - for (int i = 0; i < numExcludeHandles; i++) { - sp<IBinder> binder; - SAFE_PARCEL(input->readStrongBinder, &binder); - excludeHandles.emplace(binder); - } - SAFE_PARCEL(input->readBool, &hintForSeamlessTransition); - return NO_ERROR; -} - -status_t DisplayCaptureArgs::writeToParcel(Parcel* output) const { - SAFE_PARCEL(CaptureArgs::writeToParcel, output); - - SAFE_PARCEL(output->writeStrongBinder, displayToken); - SAFE_PARCEL(output->writeUint32, width); - SAFE_PARCEL(output->writeUint32, height); - return NO_ERROR; -} - -status_t DisplayCaptureArgs::readFromParcel(const Parcel* input) { - SAFE_PARCEL(CaptureArgs::readFromParcel, input); - - SAFE_PARCEL(input->readStrongBinder, &displayToken); - SAFE_PARCEL(input->readUint32, &width); - SAFE_PARCEL(input->readUint32, &height); - return NO_ERROR; -} - -status_t LayerCaptureArgs::writeToParcel(Parcel* output) const { - SAFE_PARCEL(CaptureArgs::writeToParcel, output); - - SAFE_PARCEL(output->writeStrongBinder, layerHandle); - SAFE_PARCEL(output->writeBool, childrenOnly); - return NO_ERROR; -} - -status_t LayerCaptureArgs::readFromParcel(const Parcel* input) { - SAFE_PARCEL(CaptureArgs::readFromParcel, input); - - SAFE_PARCEL(input->readStrongBinder, &layerHandle); - - SAFE_PARCEL(input->readBool, &childrenOnly); - return NO_ERROR; -} - -}; // namespace gui - ReleaseCallbackId BufferData::generateReleaseCallbackId() const { uint64_t bufferId; if (buffer) { diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 4a8df9e1bb..66e7ddd915 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,7 +43,7 @@ #include <ui/GraphicBuffer.h> #include <ui/Region.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/BufferItem.h> #include <gui/ISurfaceComposer.h> @@ -77,9 +77,28 @@ bool isInterceptorRegistrationOp(int op) { } // namespace +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +Surface::ProducerDeathListenerProxy::ProducerDeathListenerProxy(wp<SurfaceListener> surfaceListener) + : mSurfaceListener(surfaceListener) {} + +void Surface::ProducerDeathListenerProxy::binderDied(const wp<IBinder>&) { + sp<SurfaceListener> surfaceListener = mSurfaceListener.promote(); + if (!surfaceListener) { + return; + } + + if (surfaceListener->needsDeathNotify()) { + surfaceListener->onRemoteDied(); + } +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp, const sp<IBinder>& surfaceControlHandle) : mGraphicBufferProducer(bufferProducer), +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + mSurfaceDeathListener(nullptr), +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) mCrop(Rect::EMPTY_RECT), mBufferAge(0), mGenerationNumber(0), @@ -134,6 +153,12 @@ Surface::~Surface() { if (mConnectedToCpu) { Surface::disconnect(NATIVE_WINDOW_API_CPU); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (mSurfaceDeathListener != nullptr) { + IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener); + mSurfaceDeathListener = nullptr; + } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) } sp<ISurfaceComposer> Surface::composerService() const { @@ -716,11 +741,12 @@ status_t Surface::dequeueBuffer(sp<GraphicBuffer>* buffer, sp<Fence>* outFence) return res; } -status_t Surface::queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd) { +status_t Surface::queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd, + SurfaceQueueBufferOutput* output) { if (buffer == nullptr) { return BAD_VALUE; } - return queueBuffer(buffer.get(), fd ? fd->get() : -1); + return queueBuffer(buffer.get(), fd ? fd->get() : -1, output); } status_t Surface::detachBuffer(const sp<GraphicBuffer>& buffer) { @@ -1170,7 +1196,8 @@ void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence, #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) -int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { +int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd, + SurfaceQueueBufferOutput* surfaceOutput) { ATRACE_CALL(); ALOGV("Surface::queueBuffer"); @@ -1220,16 +1247,26 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { onBufferQueuedLocked(slot, fence, output); } + if (surfaceOutput != nullptr) { + *surfaceOutput = {.bufferReplaced = output.bufferReplaced}; + } + return err; } -int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers, + std::vector<SurfaceQueueBufferOutput>* queueBufferOutputs) +#else +int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +{ ATRACE_CALL(); ALOGV("Surface::queueBuffers"); size_t numBuffers = buffers.size(); - std::vector<IGraphicBufferProducer::QueueBufferInput> queueBufferInputs(numBuffers); - std::vector<IGraphicBufferProducer::QueueBufferOutput> queueBufferOutputs; + std::vector<IGraphicBufferProducer::QueueBufferInput> igbpQueueBufferInputs(numBuffers); + std::vector<IGraphicBufferProducer::QueueBufferOutput> igbpQueueBufferOutputs; std::vector<int> bufferSlots(numBuffers, -1); std::vector<sp<Fence>> bufferFences(numBuffers); @@ -1255,12 +1292,13 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { IGraphicBufferProducer::QueueBufferInput input; getQueueBufferInputLocked(buffers[batchIdx].buffer, buffers[batchIdx].fenceFd, buffers[batchIdx].timestamp, &input); + input.slot = i; bufferFences[batchIdx] = input.fence; - queueBufferInputs[batchIdx] = input; + igbpQueueBufferInputs[batchIdx] = input; } } nsecs_t now = systemTime(); - err = mGraphicBufferProducer->queueBuffers(queueBufferInputs, &queueBufferOutputs); + err = mGraphicBufferProducer->queueBuffers(igbpQueueBufferInputs, &igbpQueueBufferOutputs); { Mutex::Autolock lock(mMutex); mLastQueueDuration = systemTime() - now; @@ -1270,9 +1308,20 @@ int Surface::queueBuffers(const std::vector<BatchQueuedBuffer>& buffers) { for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) { onBufferQueuedLocked(bufferSlots[batchIdx], bufferFences[batchIdx], - queueBufferOutputs[batchIdx]); + igbpQueueBufferOutputs[batchIdx]); + } + } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (queueBufferOutputs != nullptr) { + queueBufferOutputs->clear(); + queueBufferOutputs->resize(numBuffers); + for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) { + (*queueBufferOutputs)[batchIdx].bufferReplaced = + igbpQueueBufferOutputs[batchIdx].bufferReplaced; } } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) return err; } @@ -2033,6 +2082,7 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; mReportRemovedBuffers = reportBufferRemoval; + if (listener != nullptr) { mListenerProxy = new ProducerListenerProxy(this, listener); } @@ -2053,6 +2103,13 @@ int Surface::connect(int api, const sp<SurfaceListener>& listener, bool reportBu } mConsumerRunningBehind = (output.numPendingBuffers >= 2); + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (listener && listener->needsDeathNotify()) { + mSurfaceDeathListener = sp<ProducerDeathListenerProxy>::make(listener); + IInterface::asBinder(mGraphicBufferProducer)->linkToDeath(mSurfaceDeathListener); + } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) } if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; @@ -2093,6 +2150,14 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mConnectedToCpu = false; } } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (mSurfaceDeathListener != nullptr) { + IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener); + mSurfaceDeathListener = nullptr; + } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + return err; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index b5d9366185..df58df43be 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -43,7 +43,7 @@ #include <system/graphics.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/BufferItemConsumer.h> #include <gui/CpuConsumer.h> #include <gui/IGraphicBufferProducer.h> @@ -2051,8 +2051,9 @@ SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp<Surfa SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext, CallbackId::Type callbackType) { - auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3); + auto callbackWithContext = + std::bind(std::move(callback), callbackContext, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3); const auto& surfaceControls = mListenerCallbacks[mTransactionCompletedListener].surfaceControls; CallbackId callbackId = @@ -2066,13 +2067,15 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTrans SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCompletedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext) { - return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMPLETE); + return addTransactionCallback(std::move(callback), callbackContext, + CallbackId::Type::ON_COMPLETE); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCommittedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext) { - return addTransactionCallback(callback, callbackContext, CallbackId::Type::ON_COMMIT); + return addTransactionCallback(std::move(callback), callbackContext, + CallbackId::Type::ON_COMMIT); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect( diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index 0929b8e120..91c9a85149 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -15,7 +15,7 @@ */ #include <android/gui/ISurfaceComposer.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/WindowInfosListenerReporter.h> #include "gui/WindowInfosUpdate.h" diff --git a/libs/gui/aidl/Android.bp b/libs/gui/aidl/Android.bp index 8ed08c2644..fd035f60f5 100644 --- a/libs/gui/aidl/Android.bp +++ b/libs/gui/aidl/Android.bp @@ -28,9 +28,6 @@ filegroup { ":libgui_extra_unstructured_aidl_files", "android/gui/BitTube.aidl", - "android/gui/CaptureArgs.aidl", - "android/gui/DisplayCaptureArgs.aidl", - "android/gui/LayerCaptureArgs.aidl", "android/gui/LayerMetadata.aidl", "android/gui/ParcelableVsyncEventData.aidl", "android/gui/ScreenCaptureResults.aidl", diff --git a/libs/gui/aidl/android/gui/CaptureArgs.aidl b/libs/gui/aidl/android/gui/CaptureArgs.aidl index 9f198cae10..2bbed2b9d6 100644 --- a/libs/gui/aidl/android/gui/CaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl @@ -16,4 +16,58 @@ package android.gui; -parcelable CaptureArgs cpp_header "gui/DisplayCaptureArgs.h" rust_type "gui_aidl_types_rs::CaptureArgs"; +import android.gui.ARect; + +// Common arguments for capturing content on-screen +parcelable CaptureArgs { + const int UNSET_UID = -1; + + // Desired pixel format of the final screenshotted buffer + int /*ui::PixelFormat*/ pixelFormat = 1; + + // Crop in layer space: all content outside of the crop will not be captured. + ARect sourceCrop; + + // Scale in the x-direction for the screenshotted result. + float frameScaleX = 1.0f; + + // Scale in the y-direction for the screenshotted result. + float frameScaleY = 1.0f; + + // True if capturing secure layers is permitted + boolean captureSecureLayers = false; + + // UID whose content we want to screenshot + int uid = UNSET_UID; + + // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured + // result will be in a colorspace appropriate for capturing the display contents + // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be + // different from SRGB (byte per color), and failed when checking colors in tests. + // NOTE: In normal cases, we want the screen to be captured in display's colorspace. + int /*ui::Dataspace*/ dataspace = 0; + + // The receiver of the capture can handle protected buffer. A protected buffer has + // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour. + // Any read/write access from unprotected context will result in undefined behaviour. + // Protected contents are typically DRM contents. This has no direct implication to the + // secure property of the surface, which is specified by the application explicitly to avoid + // the contents being accessed/captured by screenshot or unsecure display. + boolean allowProtected = false; + + // True if the content should be captured in grayscale + boolean grayscale = false; + + // List of layers to exclude capturing from + IBinder[] excludeHandles; + + // Hint that the caller will use the screenshot animation as part of a transition animation. + // The canonical example would be screen rotation - in such a case any color shift in the + // screenshot is a detractor so composition in the display's colorspace is required. + // Otherwise, the system may choose a colorspace that is more appropriate for use-cases + // such as file encoding or for blending HDR content into an ap's UI, where the display's + // exact colorspace is not an appropriate intermediate result. + // Note that if the caller is requesting a specific dataspace, this hint does nothing. + boolean hintForSeamlessTransition = false; +} + diff --git a/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl index fc97dbf03d..e00a2dfa82 100644 --- a/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl @@ -16,5 +16,18 @@ package android.gui; -parcelable DisplayCaptureArgs cpp_header "gui/DisplayCaptureArgs.h" rust_type "gui_aidl_types_rs::DisplayCaptureArgs"; +import android.gui.CaptureArgs; + +// Arguments for screenshotting an entire display +parcelable DisplayCaptureArgs { + CaptureArgs captureArgs; + + // The display that we want to screenshot + IBinder displayToken; + + // The width of the render area when we screenshot + int width = 0; + // The length of the render area when we screenshot + int height = 0; +} diff --git a/libs/gui/aidl/android/gui/JankData.aidl b/libs/gui/aidl/android/gui/JankData.aidl index 7ea9d22ecf..ec13681182 100644 --- a/libs/gui/aidl/android/gui/JankData.aidl +++ b/libs/gui/aidl/android/gui/JankData.aidl @@ -29,7 +29,17 @@ parcelable JankData { int jankType; /** - * Expected duration in nanoseconds of this frame. + * Time between frames in nanoseconds. */ long frameIntervalNs; + + /** + * Time allocated to the application to render this frame. + */ + long scheduledAppFrameTimeNs; + + /** + * Time taken by the application to render this frame. + */ + long actualAppFrameTimeNs; } diff --git a/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl index 18d293f211..004c35a5ce 100644 --- a/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl @@ -16,4 +16,15 @@ package android.gui; -parcelable LayerCaptureArgs cpp_header "gui/LayerCaptureArgs.h" rust_type "gui_aidl_types_rs::LayerCaptureArgs"; +import android.gui.CaptureArgs; + +// Arguments for capturing a layer and/or its children +parcelable LayerCaptureArgs { + CaptureArgs captureArgs; + + // The Layer that we may want to capture. We would also capture its children + IBinder layerHandle; + // True if we don't actually want to capture the layer and want to capture + // its children instead. + boolean childrenOnly = false; +} diff --git a/libs/gui/include/gui/AidlStatusUtil.h b/libs/gui/include/gui/AidlUtil.h index 55be27bf35..a3ecd84ba1 100644 --- a/libs/gui/include/gui/AidlStatusUtil.h +++ b/libs/gui/include/gui/AidlUtil.h @@ -16,9 +16,11 @@ #pragma once +#include <android/gui/ARect.h> #include <binder/Status.h> +#include <ui/Rect.h> -// Extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h +// Originally extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h namespace android::gui::aidl_utils { /** @@ -68,7 +70,7 @@ static inline status_t statusTFromExceptionCode(int32_t exceptionCode) { * * return_type method(type0 param0, ...) */ -static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) { +static inline status_t statusTFromBinderStatus(const ::android::binder::Status& status) { return status.isOk() ? OK // check OK, : status.serviceSpecificErrorCode() // service-side error, not standard Java exception // (fromServiceSpecificError) @@ -84,8 +86,8 @@ static inline status_t statusTFromBinderStatus(const ::android::binder::Status & * where Java callers expect an exception, not an integer return value. */ static inline ::android::binder::Status binderStatusFromStatusT( - status_t status, const char *optionalMessage = nullptr) { - const char *const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage; + status_t status, const char* optionalMessage = nullptr) { + const char* const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage; // From binder::Status instructions: // Prefer a generic exception code when possible, then a service specific // code, and finally a status_t for low level failures or legacy support. @@ -111,4 +113,26 @@ static inline ::android::binder::Status binderStatusFromStatusT( return Status::fromServiceSpecificError(status, emptyIfNull); } +static inline Rect fromARect(ARect rect) { + return Rect(rect.left, rect.top, rect.right, rect.bottom); +} + +static inline ARect toARect(Rect rect) { + ARect aRect; + + aRect.left = rect.left; + aRect.top = rect.top; + aRect.right = rect.right; + aRect.bottom = rect.bottom; + return aRect; +} + +static inline ARect toARect(int32_t left, int32_t top, int32_t right, int32_t bottom) { + return toARect(Rect(left, top, right, bottom)); +} + +static inline ARect toARect(int32_t width, int32_t height) { + return toARect(Rect(width, height)); +} + } // namespace android::gui::aidl_utils diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 4dafc57734..0a81126c7d 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -103,15 +103,21 @@ public: void onFrameDequeued(const uint64_t) override; void onFrameCancelled(const uint64_t) override; + TransactionCompletedCallbackTakesContext makeTransactionCommittedCallbackThunk(); void transactionCommittedCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); + + TransactionCompletedCallbackTakesContext makeTransactionCallbackThunk(); virtual void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence, const std::vector<SurfaceControlStats>& stats); + + ReleaseBufferCallback makeReleaseBufferCallbackThunk(); void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount); void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence, std::optional<uint32_t> currentMaxAcquiredBufferCount, bool fakeRelease) REQUIRES(mMutex); + bool syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback, bool acquireSingleBuffer = true); void stopContinuousSyncTransaction(); @@ -198,9 +204,16 @@ private: // latch stale buffers and that we don't wait on barriers from an old producer. uint32_t mProducerId = 0; + class BLASTBufferItem : public BufferItem { + public: + // True if BBQBufferQueueProducer is disconnected after the buffer is acquried but + // before it is released. + bool disconnectedAfterAcquired{false}; + }; + // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the // buffer or the buffer has been presented and a new buffer is ready to be presented. - std::unordered_map<ReleaseCallbackId, BufferItem, ReleaseBufferCallbackIdHash> mSubmitted + std::unordered_map<ReleaseCallbackId, BLASTBufferItem, ReleaseBufferCallbackIdHash> mSubmitted GUARDED_BY(mMutex); // Keep a queue of the released buffers instead of immediately releasing @@ -318,6 +331,51 @@ private: std::function<void(const std::string&)> mTransactionHangCallback; std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex); + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + class BufferReleaseReader { + public: + BufferReleaseReader() = default; + BufferReleaseReader(std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint>); + BufferReleaseReader& operator=(BufferReleaseReader&&); + + // Block until we can read a buffer release message. + // + // Returns: + // * OK if a ReleaseCallbackId and Fence were successfully read. + // * WOULD_BLOCK if the blocking read was interrupted by interruptBlockingRead. + // * UNKNOWN_ERROR if something went wrong. + status_t readBlocking(ReleaseCallbackId& outId, sp<Fence>& outReleaseFence, + uint32_t& outMaxAcquiredBufferCount); + + // Signals the reader's eventfd to wake up any threads waiting on readBlocking. + void interruptBlockingRead(); + + private: + std::mutex mMutex; + std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mEndpoint GUARDED_BY(mMutex); + android::base::unique_fd mEpollFd; + android::base::unique_fd mEventFd; + }; + + // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to + // the client. See BBQBufferQueueProducer::dequeueBuffer for details. + std::shared_ptr<BufferReleaseReader> mBufferReleaseReader; + std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer; + + class BufferReleaseThread { + public: + BufferReleaseThread() = default; + ~BufferReleaseThread(); + void start(const sp<BLASTBufferQueue>&); + + private: + std::shared_ptr<std::atomic_bool> mRunning; + std::shared_ptr<BufferReleaseReader> mReader; + }; + + BufferReleaseThread mBufferReleaseThread; +#endif }; } // namespace android diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h deleted file mode 100644 index e29ce41bd5..0000000000 --- a/libs/gui/include/gui/DisplayCaptureArgs.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include <stdint.h> -#include <sys/types.h> - -#include <binder/IBinder.h> -#include <binder/Parcel.h> -#include <binder/Parcelable.h> -#include <gui/SpHash.h> -#include <ui/GraphicTypes.h> -#include <ui/PixelFormat.h> -#include <ui/Rect.h> -#include <unordered_set> - -namespace android::gui { - -struct CaptureArgs : public Parcelable { - const static int32_t UNSET_UID = -1; - virtual ~CaptureArgs() = default; - - ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888}; - Rect sourceCrop; - float frameScaleX{1}; - float frameScaleY{1}; - bool captureSecureLayers{false}; - int32_t uid{UNSET_UID}; - // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured - // result will be in a colorspace appropriate for capturing the display contents - // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be - // different from SRGB (byte per color), and failed when checking colors in tests. - // NOTE: In normal cases, we want the screen to be captured in display's colorspace. - ui::Dataspace dataspace = ui::Dataspace::UNKNOWN; - - // The receiver of the capture can handle protected buffer. A protected buffer has - // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour. - // Any read/write access from unprotected context will result in undefined behaviour. - // Protected contents are typically DRM contents. This has no direct implication to the - // secure property of the surface, which is specified by the application explicitly to avoid - // the contents being accessed/captured by screenshot or unsecure display. - bool allowProtected = false; - - bool grayscale = false; - - std::unordered_set<sp<IBinder>, SpHash<IBinder>> excludeHandles; - - // Hint that the caller will use the screenshot animation as part of a transition animation. - // The canonical example would be screen rotation - in such a case any color shift in the - // screenshot is a detractor so composition in the display's colorspace is required. - // Otherwise, the system may choose a colorspace that is more appropriate for use-cases - // such as file encoding or for blending HDR content into an ap's UI, where the display's - // exact colorspace is not an appropriate intermediate result. - // Note that if the caller is requesting a specific dataspace, this hint does nothing. - bool hintForSeamlessTransition = false; - - virtual status_t writeToParcel(Parcel* output) const; - virtual status_t readFromParcel(const Parcel* input); -}; - -struct DisplayCaptureArgs : CaptureArgs { - sp<IBinder> displayToken; - uint32_t width{0}; - uint32_t height{0}; - - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; -}; - -}; // namespace android::gui diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index 3d1be4d2eb..462081bfd2 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -116,7 +116,7 @@ public: // Public for testing. static nsecs_t snapToNextTick( nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval); - nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; }; + nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; } nsecs_t getNextCompositeDeadline(const nsecs_t now) const; nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; } diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 8fca9460aa..3aac457a09 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -867,6 +867,6 @@ class BnGraphicBufferProducer : public IGraphicBufferProducer { #endif // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif // ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 1ecc216dff..9a422fd808 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -18,6 +18,7 @@ #include <android/gui/CachingHint.h> #include <android/gui/DisplayBrightness.h> +#include <android/gui/DisplayCaptureArgs.h> #include <android/gui/FrameTimelineInfo.h> #include <android/gui/IDisplayEventConnection.h> #include <android/gui/IFpsListener.h> @@ -27,6 +28,7 @@ #include <android/gui/ITunnelModeEnabledListener.h> #include <android/gui/IWindowInfosListener.h> #include <android/gui/IWindowInfosPublisher.h> +#include <android/gui/LayerCaptureArgs.h> #include <binder/IBinder.h> #include <binder/IInterface.h> #include <gui/ITransactionCompletedListener.h> @@ -70,13 +72,6 @@ using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; using gui::SpHash; -namespace gui { - -struct DisplayCaptureArgs; -struct LayerCaptureArgs; - -} // namespace gui - namespace ui { struct DisplayMode; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index d41994589f..2cdde3255e 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -21,7 +21,9 @@ #include <stdint.h> #include <sys/types.h> +#include <android/gui/DisplayCaptureArgs.h> #include <android/gui/IWindowInfosReportedListener.h> +#include <android/gui/LayerCaptureArgs.h> #include <android/gui/TrustedPresentationThresholds.h> #include <android/native_window.h> #include <gui/IGraphicBufferProducer.h> @@ -35,9 +37,7 @@ #include <ftl/flags.h> #include <gui/BufferReleaseChannel.h> -#include <gui/DisplayCaptureArgs.h> #include <gui/ISurfaceComposer.h> -#include <gui/LayerCaptureArgs.h> #include <gui/LayerMetadata.h> #include <gui/SpHash.h> #include <gui/SurfaceControl.h> diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 39207f835f..e74f9ad1dc 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -66,6 +66,16 @@ public: virtual void onBufferAttached() {} virtual bool needsAttachNotify() { return false; } #endif + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // Called if this Surface is connected to a remote implementation and it + // dies or becomes unavailable. + virtual void onRemoteDied() {} + + // Clients will overwrite this if they want to receive a notification + // via onRemoteDied. This should return a constant value. + virtual bool needsDeathNotify() { return false; } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) }; class StubSurfaceListener : public SurfaceListener { @@ -77,6 +87,15 @@ public: virtual void onBufferDetached(int /*slot*/) override {} }; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +// Contains additional data from the queueBuffer operation. +struct SurfaceQueueBufferOutput { + // True if this queueBuffer caused a buffer to be replaced in the queue + // (and therefore not will not be acquired) + bool bufferReplaced = false; +}; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + /* * An implementation of ANativeWindow that feeds graphics buffers into a * BufferQueue. @@ -194,6 +213,14 @@ public: * in <system/window.h>. */ int setScalingMode(int mode); + virtual int setBuffersTimestamp(int64_t timestamp); + virtual int setBuffersDataSpace(ui::Dataspace dataSpace); + virtual int setCrop(Rect const* rect); + virtual int setBuffersTransform(uint32_t transform); + virtual int setBuffersStickyTransform(uint32_t transform); + virtual int setBuffersFormat(PixelFormat format); + virtual int setUsage(uint64_t reqUsage); + // See IGraphicBufferProducer::setDequeueTimeout status_t setDequeueTimeout(nsecs_t timeout); @@ -345,7 +372,12 @@ private: protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd, + SurfaceQueueBufferOutput* surfaceOutput = nullptr); +#else virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) virtual int perform(int operation, va_list args); virtual int setSwapInterval(int interval); @@ -354,16 +386,9 @@ protected: virtual int connect(int api); virtual int setBufferCount(int bufferCount); virtual int setBuffersUserDimensions(uint32_t width, uint32_t height); - virtual int setBuffersFormat(PixelFormat format); - virtual int setBuffersTransform(uint32_t transform); - virtual int setBuffersStickyTransform(uint32_t transform); - virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setBuffersDataSpace(ui::Dataspace dataSpace); virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata); virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata); virtual int setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata); - virtual int setCrop(Rect const* rect); - virtual int setUsage(uint64_t reqUsage); virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); public: @@ -411,7 +436,8 @@ public: // Queues a buffer, with an optional fd fence that captures pending work on the buffer. This // buffer must have been returned by dequeueBuffer or associated with this Surface via an // attachBuffer operation. - status_t queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd = Fence::NO_FENCE); + status_t queueBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& fd = Fence::NO_FENCE, + SurfaceQueueBufferOutput* output = nullptr); // Detaches this buffer, dissociating it from this Surface. This buffer must have been returned // by queueBuffer or associated with this Surface via an attachBuffer operation. @@ -432,8 +458,13 @@ public: int fenceFd = -1; nsecs_t timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; }; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + virtual int queueBuffers(const std::vector<BatchQueuedBuffer>& buffers, + std::vector<SurfaceQueueBufferOutput>* queueBufferOutputs = nullptr); +#else virtual int queueBuffers( const std::vector<BatchQueuedBuffer>& buffers); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; @@ -470,6 +501,21 @@ protected: sp<SurfaceListener> mSurfaceListener; }; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + class ProducerDeathListenerProxy : public IBinder::DeathRecipient { + public: + ProducerDeathListenerProxy(wp<SurfaceListener> surfaceListener); + ProducerDeathListenerProxy(ProducerDeathListenerProxy&) = delete; + + // IBinder::DeathRecipient + virtual void binderDied(const wp<IBinder>&) override; + + private: + wp<SurfaceListener> mSurfaceListener; + }; + friend class ProducerDeathListenerProxy; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + void querySupportedTimestampsLocked() const; void freeAllBuffers(); @@ -501,6 +547,13 @@ protected: // TODO: rename to mBufferProducer sp<IGraphicBufferProducer> mGraphicBufferProducer; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // mSurfaceDeathListener gets registered as mGraphicBufferProducer's + // DeathRecipient when SurfaceListener::needsDeathNotify returns true and + // gets notified when it dies. + sp<ProducerDeathListenerProxy> mSurfaceDeathListener; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // mSlots stores the buffers that have been allocated for each buffer slot. // It is initialized to null pointers, and gets filled in with the result of // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h index b7aba2b9dc..7ddac8139a 100644 --- a/libs/gui/include/gui/view/Surface.h +++ b/libs/gui/include/gui/view/Surface.h @@ -59,8 +59,9 @@ class Surface : public Parcelable { // of the full parceling to happen on its native side. status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead); - private: + std::string toString() const; +private: static String16 readMaybeEmptyString16(const Parcel* parcel); }; diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig index c367e75065..7468401b7a 100644 --- a/libs/gui/libgui_flags.aconfig +++ b/libs/gui/libgui_flags.aconfig @@ -91,3 +91,11 @@ flag { bug: "342197847" is_fixed_read_only: true } # wb_ring_buffer + +flag { + name: "wb_camera3_and_processors" + namespace: "core_graphics" + description: "Remove usage of IGBPs in the *Processor and Camera3*" + bug: "342199002" + is_fixed_read_only: true +} # wb_camera3_and_processors
\ No newline at end of file diff --git a/libs/gui/rust/aidl_types/src/lib.rs b/libs/gui/rust/aidl_types/src/lib.rs index fead018bbf..2351df0318 100644 --- a/libs/gui/rust/aidl_types/src/lib.rs +++ b/libs/gui/rust/aidl_types/src/lib.rs @@ -42,10 +42,7 @@ macro_rules! stub_unstructured_parcelable { } stub_unstructured_parcelable!(BitTube); -stub_unstructured_parcelable!(CaptureArgs); -stub_unstructured_parcelable!(DisplayCaptureArgs); stub_unstructured_parcelable!(DisplayInfo); -stub_unstructured_parcelable!(LayerCaptureArgs); stub_unstructured_parcelable!(LayerDebugInfo); stub_unstructured_parcelable!(LayerMetadata); stub_unstructured_parcelable!(ParcelableVsyncEventData); diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 1b216e9063..f07747f32f 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -12,6 +12,34 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +aidl_interface { + name: "libgui_test_server_aidl", + unstable: true, + srcs: ["testserver/aidl/**/*.aidl"], + local_include_dir: "testserver/aidl", + include_dirs: [ + "frameworks/native/aidl/gui", + ], + backend: { + cpp: { + enabled: true, + additional_shared_libraries: [ + "libgui", + "libui", + ], + }, + java: { + enabled: false, + }, + ndk: { + enabled: false, + }, + rust: { + enabled: false, + }, + }, +} + cc_test { name: "libgui_test", test_suites: ["device-tests"], @@ -30,7 +58,6 @@ cc_test { ], srcs: [ - "LibGuiMain.cpp", // Custom gtest entrypoint "BLASTBufferQueue_test.cpp", "BufferItemConsumer_test.cpp", "BufferQueue_test.cpp", @@ -38,24 +65,29 @@ cc_test { "Choreographer_test.cpp", "CompositorTiming_test.cpp", "CpuConsumer_test.cpp", - "EndToEndNativeInputTest.cpp", - "FrameRateUtilsTest.cpp", - "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", + "DisplayInfo_test.cpp", + "EndToEndNativeInputTest.cpp", "FillBuffer.cpp", + "FrameRateUtilsTest.cpp", "GLTest.cpp", "IGraphicBufferProducer_test.cpp", + "LibGuiMain.cpp", // Custom gtest entrypoint "Malicious.cpp", "MultiTextureConsumer_test.cpp", "RegionSampling_test.cpp", "StreamSplitter_test.cpp", + "Surface_test.cpp", "SurfaceTextureClient_test.cpp", "SurfaceTextureFBO_test.cpp", + "SurfaceTextureGL_test.cpp", "SurfaceTextureGLThreadToGL_test.cpp", "SurfaceTextureGLToGL_test.cpp", - "SurfaceTextureGL_test.cpp", "SurfaceTextureMultiContextGL_test.cpp", - "Surface_test.cpp", + "TestServer_test.cpp", + "testserver/TestServer.cpp", + "testserver/TestServerClient.cpp", + "testserver/TestServerHost.cpp", "TextureRenderer.cpp", "VsyncEventData_test.cpp", "WindowInfo_test.cpp", @@ -66,10 +98,17 @@ cc_test { "android.hardware.configstore-utils", "libSurfaceFlingerProp", "libGLESv1_CM", + "libgui_test_server_aidl-cpp", "libinput", "libnativedisplay", ], + // This needs to get copied over for the test since it's not part of the + // platform. + data_libs: [ + "libgui_test_server_aidl-cpp", + ], + static_libs: [ "libgmock", ], diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 6852589e32..eb2a61d151 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -20,7 +20,7 @@ #include <android-base/thread_annotations.h> #include <android/hardware/graphics/common/1.2/types.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> #include <gui/FrameTimestamps.h> @@ -229,7 +229,8 @@ protected: ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ mRootSurfaceControl->getHandle()); - mCaptureArgs.sourceCrop = Rect(ui::Size(mDisplayWidth, mDisplayHeight)); + mCaptureArgs.captureArgs.sourceCrop = + gui::aidl_utils::toARect(mDisplayWidth, mDisplayHeight); mCaptureArgs.layerHandle = mRootSurfaceControl->getHandle(); } diff --git a/libs/gui/tests/LibGuiMain.cpp b/libs/gui/tests/LibGuiMain.cpp index 10f7207588..7c7c2cc30f 100644 --- a/libs/gui/tests/LibGuiMain.cpp +++ b/libs/gui/tests/LibGuiMain.cpp @@ -14,8 +14,15 @@ * limitations under the License. */ -#include "gtest/gtest.h" -#include "log/log.h" +#include <android-base/unique_fd.h> +#include <gtest/gtest.h> +#include <log/log.h> + +#include "testserver/TestServer.h" +#include "testserver/TestServerClient.h" +#include "testserver/TestServerHost.h" + +using namespace android; namespace { @@ -32,7 +39,34 @@ class TestCaseLogger : public ::testing::EmptyTestEventListener { } // namespace int main(int argc, char** argv) { + // There are three modes that we can run in to support the libgui TestServer: + // + // - libgui_test : normal mode, runs tests and fork/execs the testserver host process + // - libgui_test --test-server-host $recvPipeFd $sendPipeFd : TestServerHost mode, listens on + // $recvPipeFd for commands and sends responses over $sendPipeFd + // - libgui_test --test-server $name : TestServer mode, starts a ITestService binder service + // under $name + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + if (arg == "--test-server-host") { + LOG_ALWAYS_FATAL_IF(argc < (i + 2), "--test-server-host requires two pipe fds"); + // Note that the send/recv are from our perspective. + base::unique_fd recvPipeFd = base::unique_fd(atoi(argv[i + 1])); + base::unique_fd sendPipeFd = base::unique_fd(atoi(argv[i + 2])); + return TestServerHostMain(argv[0], std::move(sendPipeFd), std::move(recvPipeFd)); + } + if (arg == "--test-server") { + LOG_ALWAYS_FATAL_IF(argc < (i + 1), "--test-server requires a name"); + return TestServerMain(argv[i + 1]); + } + } testing::InitGoogleTest(&argc, argv); testing::UnitTest::GetInstance()->listeners().Append(new TestCaseLogger()); + + // This has to be run *before* any test initialization, because it fork/execs a TestServerHost, + // which will later create new binder service. You can't do that in a forked thread after you've + // initialized any binder stuff, which some tests do. + TestServerClient::InitializeOrDie(argv[0]); + return RUN_ALL_TESTS(); }
\ No newline at end of file diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index 223e4b6cbd..a0d8c53385 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -19,7 +19,7 @@ #include <android/gui/BnRegionSamplingListener.h> #include <binder/ProcessState.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/DisplayEventReceiver.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 8ab8783c4c..88893b64ba 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "gui/view/Surface.h" #include "Constants.h" #include "MockConsumer.h" @@ -27,7 +28,7 @@ #include <binder/ProcessState.h> #include <com_android_graphics_libgui_flags.h> #include <configstore/Utils.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/BufferItemConsumer.h> #include <gui/BufferQueue.h> #include <gui/CpuConsumer.h> @@ -49,10 +50,15 @@ #include <utils/Errors.h> #include <utils/String8.h> +#include <chrono> #include <cstddef> +#include <cstdint> +#include <future> #include <limits> #include <thread> +#include "testserver/TestServerClient.h" + namespace android { using namespace std::chrono_literals; @@ -105,6 +111,18 @@ private: std::vector<sp<GraphicBuffer>> mDiscardedBuffers; }; +class DeathWatcherListener : public StubSurfaceListener { +public: + virtual void onRemoteDied() { mDiedPromise.set_value(true); } + + virtual bool needsDeathNotify() { return true; } + + std::future<bool> getDiedFuture() { return mDiedPromise.get_future(); } + +private: + std::promise<bool> mDiedPromise; +}; + class SurfaceTest : public ::testing::Test { protected: SurfaceTest() { @@ -2363,6 +2381,142 @@ TEST_F(SurfaceTest, QueueAcquireReleaseDequeue_CalledInStack_DoesNotDeadlock) { EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU)); } + +TEST_F(SurfaceTest, ViewSurface_toString) { + view::Surface surface{}; + EXPECT_EQ("", surface.toString()); + + surface.name = String16("name"); + EXPECT_EQ("name", surface.toString()); +} + +TEST_F(SurfaceTest, TestRemoteSurfaceDied_CallbackCalled) { + sp<TestServerClient> testServer = TestServerClient::Create(); + sp<IGraphicBufferProducer> producer = testServer->CreateProducer(); + EXPECT_NE(nullptr, producer); + + sp<Surface> surface = sp<Surface>::make(producer); + sp<DeathWatcherListener> deathWatcher = sp<DeathWatcherListener>::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher)); + + auto diedFuture = deathWatcher->getDiedFuture(); + EXPECT_EQ(OK, testServer->Kill()); + + diedFuture.wait(); + EXPECT_TRUE(diedFuture.get()); +} + +TEST_F(SurfaceTest, TestRemoteSurfaceDied_Disconnect_CallbackNotCalled) { + sp<TestServerClient> testServer = TestServerClient::Create(); + sp<IGraphicBufferProducer> producer = testServer->CreateProducer(); + EXPECT_NE(nullptr, producer); + + sp<Surface> surface = sp<Surface>::make(producer); + sp<DeathWatcherListener> deathWatcher = sp<DeathWatcherListener>::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher)); + EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU)); + + auto watcherDiedFuture = deathWatcher->getDiedFuture(); + EXPECT_EQ(OK, testServer->Kill()); + + std::future_status status = watcherDiedFuture.wait_for(std::chrono::seconds(1)); + EXPECT_EQ(std::future_status::timeout, status); +} + +TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements) { + sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(GRALLOC_USAGE_SW_READ_OFTEN); + ASSERT_EQ(OK, consumer->setMaxBufferCount(3)); + ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1)); + + sp<Surface> surface = consumer->getSurface(); + sp<StubSurfaceListener> listener = sp<StubSurfaceListener>::make(); + + // Async mode sets up an extra buffer so the surface can queue it without waiting. + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(1)); + ASSERT_EQ(OK, surface->setAsyncMode(true)); + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + + sp<GraphicBuffer> buffer; + sp<Fence> fence; + SurfaceQueueBufferOutput output; + BufferItem item; + + // We can queue directly, without an output arg. + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence)); + EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0)); + EXPECT_EQ(OK, consumer->releaseBuffer(item)); + + // We can queue with an output arg, and that we don't expect to see a replacement. + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output)); + EXPECT_FALSE(output.bufferReplaced); + + // We expect see a replacement when we queue a second buffer in async mode, and the consumer + // hasn't acquired the first one yet. + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output)); + EXPECT_TRUE(output.bufferReplaced); +} + +TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements_Plural) { + sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(GRALLOC_USAGE_SW_READ_OFTEN); + ASSERT_EQ(OK, consumer->setMaxBufferCount(4)); + ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1)); + + sp<Surface> surface = consumer->getSurface(); + consumer->setName(String8("TRPTest")); + sp<StubSurfaceListener> listener = sp<StubSurfaceListener>::make(); + + // Async mode sets up an extra buffer so the surface can queue it without waiting. + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(2)); + ASSERT_EQ(OK, surface->setAsyncMode(true)); + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + + // dequeueBuffers requires a vector of a certain size: + std::vector<Surface::BatchBuffer> buffers(2); + std::vector<Surface::BatchQueuedBuffer> queuedBuffers; + std::vector<SurfaceQueueBufferOutput> outputs; + BufferItem item; + + auto moveBuffersToQueuedBuffers = [&]() { + EXPECT_EQ(2u, buffers.size()); + EXPECT_NE(nullptr, buffers[0].buffer); + EXPECT_NE(nullptr, buffers[1].buffer); + + queuedBuffers.clear(); + for (auto& buffer : buffers) { + auto& queuedBuffer = queuedBuffers.emplace_back(); + queuedBuffer.buffer = buffer.buffer; + queuedBuffer.fenceFd = buffer.fenceFd; + queuedBuffer.timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + } + buffers = {{}, {}}; + }; + + // We can queue directly, without an output arg. + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + moveBuffersToQueuedBuffers(); + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers)); + EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0)); + EXPECT_EQ(OK, consumer->releaseBuffer(item)); + + // We can queue with an output arg. Only the second one should be replaced. + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + moveBuffersToQueuedBuffers(); + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs)); + EXPECT_EQ(2u, outputs.size()); + EXPECT_FALSE(outputs[0].bufferReplaced); + EXPECT_TRUE(outputs[1].bufferReplaced); + + // Since we haven't acquired anything, both queued buffers will replace the original one. + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + moveBuffersToQueuedBuffers(); + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs)); + EXPECT_EQ(2u, outputs.size()); + EXPECT_TRUE(outputs[0].bufferReplaced); + EXPECT_TRUE(outputs[1].bufferReplaced); +} #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) } // namespace android diff --git a/libs/gui/tests/TestServer_test.cpp b/libs/gui/tests/TestServer_test.cpp new file mode 100644 index 0000000000..d6407820ff --- /dev/null +++ b/libs/gui/tests/TestServer_test.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2024 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 <gtest/gtest.h> + +#include <SurfaceFlingerProperties.h> +#include <android/gui/IDisplayEventConnection.h> +#include <android/gui/ISurfaceComposer.h> +#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <android/hardware_buffer.h> +#include <binder/ProcessState.h> +#include <com_android_graphics_libgui_flags.h> +#include <configstore/Utils.h> +#include <gui/AidlUtil.h> +#include <gui/BufferItemConsumer.h> +#include <gui/BufferQueue.h> +#include <gui/CpuConsumer.h> +#include <gui/IConsumerListener.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/ISurfaceComposer.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/SyncScreenCaptureListener.h> +#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> +#include <sys/types.h> +#include <system/window.h> +#include <ui/BufferQueueDefs.h> +#include <ui/DisplayMode.h> +#include <ui/GraphicBuffer.h> +#include <ui/Rect.h> +#include <utils/Errors.h> +#include <utils/String8.h> + +#include <cstddef> +#include <limits> +#include <thread> + +#include "binder/IInterface.h" +#include "testserver/TestServerClient.h" + +namespace android { + +namespace { + +class TestServerTest : public ::testing::Test { +protected: + TestServerTest() { ProcessState::self()->startThreadPool(); } +}; + +} // namespace + +TEST_F(TestServerTest, Create) { + EXPECT_NE(nullptr, TestServerClient::Create()); +} + +TEST_F(TestServerTest, CreateProducer) { + sp<TestServerClient> client = TestServerClient::Create(); + EXPECT_NE(nullptr, client->CreateProducer()); +} + +TEST_F(TestServerTest, KillServer) { + class DeathWaiter : public IBinder::DeathRecipient { + public: + virtual void binderDied(const wp<IBinder>&) override { mPromise.set_value(true); } + std::future<bool> getFuture() { return mPromise.get_future(); } + + std::promise<bool> mPromise; + }; + + sp<TestServerClient> client = TestServerClient::Create(); + sp<IGraphicBufferProducer> producer = client->CreateProducer(); + EXPECT_NE(nullptr, producer); + + sp<DeathWaiter> deathWaiter = sp<DeathWaiter>::make(); + EXPECT_EQ(OK, IInterface::asBinder(producer)->linkToDeath(deathWaiter)); + + auto deathWaiterFuture = deathWaiter->getFuture(); + EXPECT_EQ(OK, client->Kill()); + EXPECT_EQ(nullptr, client->CreateProducer()); + + EXPECT_TRUE(deathWaiterFuture.get()); +} + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServer.cpp b/libs/gui/tests/testserver/TestServer.cpp new file mode 100644 index 0000000000..cd8824e355 --- /dev/null +++ b/libs/gui/tests/testserver/TestServer.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2024 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_TAG "TestServer" + +#include <android-base/stringprintf.h> +#include <binder/IInterface.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <binder/Status.h> +#include <gui/BufferQueue.h> +#include <gui/IConsumerListener.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/view/Surface.h> +#include <libgui_test_server/BnTestServer.h> +#include <log/log.h> +#include <utils/Errors.h> + +#include <cstdint> +#include <cstdlib> +#include <memory> +#include <mutex> +#include <vector> + +#include <fcntl.h> +#include <unistd.h> + +#include "TestServer.h" + +namespace android { + +namespace { +class TestConsumerListener : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem&) override {} + virtual void onBuffersReleased() override {} + virtual void onSidebandStreamChanged() override {} +}; + +class TestServiceImpl : public libgui_test_server::BnTestServer { +public: + TestServiceImpl(const char* name) : mName(name) {} + + virtual binder::Status createProducer(view::Surface* out) override { + std::lock_guard<std::mutex> lock(mMutex); + + BufferQueueHolder bq; + BufferQueue::createBufferQueue(&bq.producer, &bq.consumer); + sp<TestConsumerListener> listener = sp<TestConsumerListener>::make(); + bq.consumer->consumerConnect(listener, /*controlledByApp*/ true); + + uint64_t id = 0; + bq.producer->getUniqueId(&id); + std::string name = base::StringPrintf("%s-%" PRIu64, mName, id); + + out->name = String16(name.c_str()); + out->graphicBufferProducer = bq.producer; + mBqs.push_back(std::move(bq)); + + return binder::Status::ok(); + } + + virtual binder::Status killNow() override { + ALOGE("LibGUI Test Service %s dying in response to killNow", mName); + _exit(0); + // Not reached: + return binder::Status::ok(); + } + +private: + std::mutex mMutex; + const char* mName; + + struct BufferQueueHolder { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + }; + + std::vector<BufferQueueHolder> mBqs; +}; +} // namespace + +int TestServerMain(const char* name) { + ProcessState::self()->startThreadPool(); + + sp<TestServiceImpl> testService = sp<TestServiceImpl>::make(name); + ALOGE("service"); + sp<IServiceManager> serviceManager(defaultServiceManager()); + LOG_ALWAYS_FATAL_IF(OK != serviceManager->addService(String16(name), testService)); + + ALOGD("LibGUI Test Service %s STARTED", name); + + IPCThreadState::self()->joinThreadPool(); + + ALOGW("LibGUI Test Service %s DIED", name); + + return 0; +} + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/include/gui/LayerCaptureArgs.h b/libs/gui/tests/testserver/TestServer.h index fae2bcc787..4226f1bb09 100644 --- a/libs/gui/include/gui/LayerCaptureArgs.h +++ b/libs/gui/tests/testserver/TestServer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2024 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. @@ -16,19 +16,16 @@ #pragma once -#include <stdint.h> -#include <sys/types.h> +namespace android { -#include <gui/DisplayCaptureArgs.h> - -namespace android::gui { - -struct LayerCaptureArgs : CaptureArgs { - sp<IBinder> layerHandle; - bool childrenOnly{false}; - - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; -}; +/* + * Main method for a libgui ITestServer server. + * + * This must be called without any binder setup having been done, because you can't fork and do + * binder things once ProcessState is set up. + * @param name The service name of the test server to start. + * @return retcode + */ +int TestServerMain(const char* name); -}; // namespace android::gui +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerClient.cpp b/libs/gui/tests/testserver/TestServerClient.cpp new file mode 100644 index 0000000000..e388074675 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerClient.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2024 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 <sys/wait.h> +#include <cerrno> +#define LOG_TAG "TestServerClient" + +#include <android-base/stringprintf.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <libgui_test_server/ITestServer.h> +#include <log/log.h> +#include <utils/Errors.h> + +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/types.h> +#include <unistd.h> + +#include <atomic> +#include <csignal> +#include <cstdlib> +#include <mutex> +#include <string> + +#include "TestServerClient.h" +#include "TestServerCommon.h" + +namespace android { + +namespace { + +std::string GetUniqueServiceName() { + static std::atomic<int> uniqueId = 1; + + pid_t pid = getpid(); + int id = uniqueId++; + return base::StringPrintf("Libgui-TestServer-%d-%d", pid, id); +} + +struct RemoteTestServerHostHolder { + RemoteTestServerHostHolder(pid_t pid, int sendFd, int recvFd) + : mPid(pid), mSendFd(sendFd), mRecvFd(recvFd) {} + ~RemoteTestServerHostHolder() { + std::lock_guard lock(mMutex); + + kill(mPid, SIGKILL); + close(mSendFd); + close(mRecvFd); + } + + pid_t CreateTestServerOrDie(std::string name) { + std::lock_guard lock(mMutex); + + CreateServerRequest request; + strlcpy(request.name, name.c_str(), sizeof(request.name) / sizeof(request.name[0])); + + ssize_t bytes = write(mSendFd, &request, sizeof(request)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(request)); + + CreateServerResponse response; + bytes = read(mRecvFd, &response, sizeof(response)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(response)); + + return response.pid; + } + +private: + std::mutex mMutex; + + pid_t mPid; + int mSendFd; + int mRecvFd; +}; + +std::unique_ptr<RemoteTestServerHostHolder> g_remoteTestServerHostHolder = nullptr; + +} // namespace + +void TestServerClient::InitializeOrDie(const char* filename) { + int sendPipeFds[2]; + int ret = pipe(sendPipeFds); + LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess send pipe"); + + int recvPipeFds[2]; + ret = pipe(recvPipeFds); + LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess recv pipe"); + + pid_t childPid = fork(); + LOG_ALWAYS_FATAL_IF(childPid < 0, "Unable to fork child process"); + + if (childPid == 0) { + // We forked! + close(sendPipeFds[1]); + close(recvPipeFds[0]); + + // We'll be reading from the parent's "send" and writing to the parent's "recv". + std::string sendPipe = std::to_string(sendPipeFds[0]); + std::string recvPipe = std::to_string(recvPipeFds[1]); + char* args[] = { + const_cast<char*>(filename), + const_cast<char*>("--test-server-host"), + const_cast<char*>(sendPipe.c_str()), + const_cast<char*>(recvPipe.c_str()), + nullptr, + }; + + ret = execv(filename, args); + ALOGE("Failed to exec libguiTestServer. ret=%d errno=%d (%s)", ret, errno, strerror(errno)); + status_t status = -errno; + write(recvPipeFds[1], &status, sizeof(status)); + _exit(EXIT_FAILURE); + } + + close(sendPipeFds[0]); + close(recvPipeFds[1]); + + // Check for an OK status that the host started. If so, we're good to go. + status_t status; + ret = read(recvPipeFds[0], &status, sizeof(status)); + LOG_ALWAYS_FATAL_IF(ret != sizeof(status), "Unable to read from pipe: %d", ret); + LOG_ALWAYS_FATAL_IF(OK != status, "Pipe returned failed status: %d", status); + + g_remoteTestServerHostHolder = + std::make_unique<RemoteTestServerHostHolder>(childPid, sendPipeFds[1], recvPipeFds[0]); +} + +sp<TestServerClient> TestServerClient::Create() { + std::string serviceName = GetUniqueServiceName(); + + pid_t childPid = g_remoteTestServerHostHolder->CreateTestServerOrDie(serviceName); + ALOGD("Created child server %s with pid %d", serviceName.c_str(), childPid); + + sp<libgui_test_server::ITestServer> server = + waitForService<libgui_test_server::ITestServer>(String16(serviceName.c_str())); + LOG_ALWAYS_FATAL_IF(server == nullptr); + ALOGD("Created connected to child server %s", serviceName.c_str()); + + return sp<TestServerClient>::make(server); +} + +TestServerClient::TestServerClient(const sp<libgui_test_server::ITestServer>& server) + : mServer(server) {} + +TestServerClient::~TestServerClient() { + Kill(); +} + +sp<IGraphicBufferProducer> TestServerClient::CreateProducer() { + std::lock_guard<std::mutex> lock(mMutex); + + if (!mIsAlive) { + return nullptr; + } + + view::Surface surface; + binder::Status status = mServer->createProducer(&surface); + + if (!status.isOk()) { + ALOGE("Failed to create remote producer. Error: %s", status.exceptionMessage().c_str()); + return nullptr; + } + + if (!surface.graphicBufferProducer) { + ALOGE("Remote producer returned no IGBP."); + return nullptr; + } + + return surface.graphicBufferProducer; +} + +status_t TestServerClient::Kill() { + std::lock_guard<std::mutex> lock(mMutex); + if (!mIsAlive) { + return DEAD_OBJECT; + } + + mServer->killNow(); + mServer = nullptr; + mIsAlive = false; + + return OK; +} + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerClient.h b/libs/gui/tests/testserver/TestServerClient.h new file mode 100644 index 0000000000..53296344a3 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerClient.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 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 <libgui_test_server/ITestServer.h> +#include <utils/RefBase.h> + +namespace android { + +class TestServerClient : public RefBase { +public: + static void InitializeOrDie(const char* filename); + static sp<TestServerClient> Create(); + + TestServerClient(const sp<libgui_test_server::ITestServer>& server); + virtual ~TestServerClient() override; + + sp<IGraphicBufferProducer> CreateProducer(); + status_t Kill(); + +private: + std::mutex mMutex; + + sp<libgui_test_server::ITestServer> mServer; + bool mIsAlive = true; +}; + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerCommon.h b/libs/gui/tests/testserver/TestServerCommon.h new file mode 100644 index 0000000000..7370f20ef8 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerCommon.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 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 <fcntl.h> + +namespace android { + +/* + * Test -> TestServerHost Request to create a new ITestServer fork. + */ +struct CreateServerRequest { + /* + * Service name for new ITestServer. + */ + char name[128]; +}; + +/* + * TestServerHost -> Test Response for creating an ITestServer fork. + */ +struct CreateServerResponse { + /* + * pid of new ITestServer. + */ + pid_t pid; +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServerHost.cpp b/libs/gui/tests/testserver/TestServerHost.cpp new file mode 100644 index 0000000000..696c3b9817 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerHost.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2024 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_TAG "TestServerHost" + +#include <android-base/unique_fd.h> +#include <binder/IInterface.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <binder/Status.h> +#include <gui/BufferQueue.h> +#include <gui/IConsumerListener.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <libgui_test_server/BnTestServer.h> +#include <log/log.h> +#include <utils/Errors.h> + +#include <memory> +#include <vector> + +#include <fcntl.h> +#include <unistd.h> +#include <cstddef> +#include <cstdlib> + +#include "TestServerCommon.h" +#include "TestServerHost.h" + +namespace android { + +namespace { + +pid_t ForkTestServer(const char* filename, char* name) { + pid_t childPid = fork(); + LOG_ALWAYS_FATAL_IF(childPid == -1); + + if (childPid != 0) { + return childPid; + } + + // We forked! + const char* test_server_flag = "--test-server"; + char* args[] = { + const_cast<char*>(filename), + const_cast<char*>(test_server_flag), + name, + nullptr, + }; + + int ret = execv(filename, args); + ALOGE("Failed to exec libgui_test as a TestServer. ret=%d errno=%d (%s)", ret, errno, + strerror(errno)); + _exit(EXIT_FAILURE); +} + +} // namespace + +int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd, + base::unique_fd recvPipeFd) { + status_t status = OK; + LOG_ALWAYS_FATAL_IF(sizeof(status) != write(sendPipeFd.get(), &status, sizeof(status))); + + ALOGE("Launched TestServerHost"); + + while (true) { + CreateServerRequest request = {}; + ssize_t bytes = read(recvPipeFd.get(), &request, sizeof(request)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(request)); + pid_t childPid = ForkTestServer(filename, request.name); + + CreateServerResponse response = {}; + response.pid = childPid; + bytes = write(sendPipeFd.get(), &response, sizeof(response)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(response)); + } + + return 0; +} + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServerHost.h b/libs/gui/tests/testserver/TestServerHost.h new file mode 100644 index 0000000000..df22c0c3fe --- /dev/null +++ b/libs/gui/tests/testserver/TestServerHost.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android-base/unique_fd.h> + +#include <string> + +namespace android { + +/* + * Main method for a host process for TestServers. + * + * This must be called without any binder setup having been done, because you can't fork and do + * binder things once ProcessState is set up. + * @param filename File name of this binary / the binary to execve into + * @param sendPipeFd Pipe FD to send data to. + * @param recvPipeFd Pipe FD to receive data from. + * @return retcode + */ +int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd, + base::unique_fd recvPipeFd); + +} // namespace android diff --git a/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl new file mode 100644 index 0000000000..c939ea00c1 --- /dev/null +++ b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl @@ -0,0 +1,12 @@ +package libgui_test_server; + +import android.view.Surface; + +// Test server for libgui_test +interface ITestServer { + // Create a new producer. The server will have connected to the consumer. + Surface createProducer(); + + // Kills the server immediately. + void killNow(); +} diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index 7c15e7cf92..84c2a6ac71 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -121,5 +121,11 @@ String16 Surface::readMaybeEmptyString16(const Parcel* parcel) { return str.value_or(String16()); } +std::string Surface::toString() const { + std::stringstream out; + out << name; + return out.str(); +} + } // namespace view } // namespace android diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp index 836a97af53..c663649091 100644 --- a/libs/input/Resampler.cpp +++ b/libs/input/Resampler.cpp @@ -21,6 +21,7 @@ #include <android-base/logging.h> #include <android-base/properties.h> +#include <ftl/enum.h> #include <input/Resampler.h> #include <utils/Timers.h> @@ -56,12 +57,17 @@ constexpr std::chrono::milliseconds RESAMPLE_MAX_DELTA{20}; constexpr std::chrono::milliseconds RESAMPLE_MAX_PREDICTION{8}; +bool canResampleTool(ToolType toolType) { + return toolType == ToolType::FINGER || toolType == ToolType::MOUSE || + toolType == ToolType::STYLUS || toolType == ToolType::UNKNOWN; +} + inline float lerp(float a, float b, float alpha) { return a + alpha * (b - a); } -const PointerCoords calculateResampledCoords(const PointerCoords& a, const PointerCoords& b, - const float alpha) { +PointerCoords calculateResampledCoords(const PointerCoords& a, const PointerCoords& b, + float alpha) { // We use the value of alpha to initialize resampledCoords with the latest sample information. PointerCoords resampledCoords = (alpha < 1.0f) ? a : b; resampledCoords.isResampled = true; @@ -72,52 +78,143 @@ const PointerCoords calculateResampledCoords(const PointerCoords& a, const Point } // namespace void LegacyResampler::updateLatestSamples(const MotionEvent& motionEvent) { - const size_t motionEventSampleSize = motionEvent.getHistorySize() + 1; - for (size_t i = 0; i < motionEventSampleSize; ++i) { - Sample sample{static_cast<nanoseconds>(motionEvent.getHistoricalEventTime(i)), - *motionEvent.getPointerProperties(0), - motionEvent.getSamplePointerCoords()[i]}; - mLatestSamples.pushBack(sample); + const size_t numSamples = motionEvent.getHistorySize() + 1; + const size_t latestIndex = numSamples - 1; + const size_t secondToLatestIndex = (latestIndex > 0) ? (latestIndex - 1) : 0; + for (size_t sampleIndex = secondToLatestIndex; sampleIndex < numSamples; ++sampleIndex) { + std::vector<Pointer> pointers; + const size_t numPointers = motionEvent.getPointerCount(); + for (size_t pointerIndex = 0; pointerIndex < numPointers; ++pointerIndex) { + // getSamplePointerCoords is the vector representation of a getHistorySize by + // getPointerCount matrix. + const PointerCoords& pointerCoords = + motionEvent.getSamplePointerCoords()[sampleIndex * numPointers + pointerIndex]; + pointers.push_back( + Pointer{*motionEvent.getPointerProperties(pointerIndex), pointerCoords}); + } + mLatestSamples.pushBack( + Sample{nanoseconds{motionEvent.getHistoricalEventTime(sampleIndex)}, pointers}); } } -void LegacyResampler::interpolate(const nanoseconds resampleTime, MotionEvent& motionEvent, - const InputMessage& futureSample) const { - const Sample pastSample = mLatestSamples.back(); - const nanoseconds delta = - static_cast<nanoseconds>(futureSample.body.motion.eventTime) - pastSample.eventTime; +LegacyResampler::Sample LegacyResampler::messageToSample(const InputMessage& message) { + std::vector<Pointer> pointers; + for (uint32_t i = 0; i < message.body.motion.pointerCount; ++i) { + pointers.push_back(Pointer{message.body.motion.pointers[i].properties, + message.body.motion.pointers[i].coords}); + } + return Sample{nanoseconds{message.body.motion.eventTime}, pointers}; +} + +bool LegacyResampler::pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary) { + if (target.pointers.size() > auxiliary.pointers.size()) { + LOG_IF(INFO, debugResampling()) + << "Not resampled. Auxiliary sample has fewer pointers than target sample."; + return false; + } + for (size_t i = 0; i < target.pointers.size(); ++i) { + if (target.pointers[i].properties.id != auxiliary.pointers[i].properties.id) { + LOG_IF(INFO, debugResampling()) << "Not resampled. Pointer ID mismatch."; + return false; + } + if (target.pointers[i].properties.toolType != auxiliary.pointers[i].properties.toolType) { + LOG_IF(INFO, debugResampling()) << "Not resampled. Pointer ToolType mismatch."; + return false; + } + if (!canResampleTool(target.pointers[i].properties.toolType)) { + LOG_IF(INFO, debugResampling()) + << "Not resampled. Cannot resample " + << ftl::enum_string(target.pointers[i].properties.toolType) << " ToolType."; + return false; + } + } + return true; +} + +bool LegacyResampler::canInterpolate(const InputMessage& message) const { + LOG_IF(FATAL, mLatestSamples.empty()) + << "Not resampled. mLatestSamples must not be empty to interpolate."; + + const Sample& pastSample = *(mLatestSamples.end() - 1); + const Sample& futureSample = messageToSample(message); + + if (!pointerPropertiesResampleable(pastSample, futureSample)) { + return false; + } + + const nanoseconds delta = futureSample.eventTime - pastSample.eventTime; if (delta < RESAMPLE_MIN_DELTA) { LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns."; - return; + return false; } + return true; +} + +std::optional<LegacyResampler::Sample> LegacyResampler::attemptInterpolation( + nanoseconds resampleTime, const InputMessage& futureSample) const { + if (!canInterpolate(futureSample)) { + return std::nullopt; + } + LOG_IF(FATAL, mLatestSamples.empty()) + << "Not resampled. mLatestSamples must not be empty to interpolate."; + + const Sample& pastSample = *(mLatestSamples.end() - 1); + + const nanoseconds delta = + nanoseconds{futureSample.body.motion.eventTime} - pastSample.eventTime; const float alpha = std::chrono::duration<float, std::milli>(resampleTime - pastSample.eventTime) / delta; - const PointerCoords resampledCoords = - calculateResampledCoords(pastSample.pointer.coords, - futureSample.body.motion.pointers[0].coords, alpha); - motionEvent.addSample(resampleTime.count(), &resampledCoords, motionEvent.getId()); + std::vector<Pointer> resampledPointers; + for (size_t i = 0; i < pastSample.pointers.size(); ++i) { + const PointerCoords& resampledCoords = + calculateResampledCoords(pastSample.pointers[i].coords, + futureSample.body.motion.pointers[i].coords, alpha); + resampledPointers.push_back(Pointer{pastSample.pointers[i].properties, resampledCoords}); + } + return Sample{resampleTime, resampledPointers}; } -void LegacyResampler::extrapolate(const nanoseconds resampleTime, MotionEvent& motionEvent) const { +bool LegacyResampler::canExtrapolate() const { if (mLatestSamples.size() < 2) { - return; + LOG_IF(INFO, debugResampling()) << "Not resampled. Not enough data."; + return false; } - const Sample pastSample = *(mLatestSamples.end() - 2); - const Sample presentSample = *(mLatestSamples.end() - 1); - const nanoseconds delta = - static_cast<nanoseconds>(presentSample.eventTime - pastSample.eventTime); + + const Sample& pastSample = *(mLatestSamples.end() - 2); + const Sample& presentSample = *(mLatestSamples.end() - 1); + + if (!pointerPropertiesResampleable(presentSample, pastSample)) { + return false; + } + + const nanoseconds delta = presentSample.eventTime - pastSample.eventTime; if (delta < RESAMPLE_MIN_DELTA) { LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns."; - return; + return false; } else if (delta > RESAMPLE_MAX_DELTA) { LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too large: " << delta << "ns."; - return; + return false; + } + return true; +} + +std::optional<LegacyResampler::Sample> LegacyResampler::attemptExtrapolation( + nanoseconds resampleTime) const { + if (!canExtrapolate()) { + return std::nullopt; } + LOG_IF(FATAL, mLatestSamples.size() < 2) + << "Not resampled. mLatestSamples must have at least two samples to extrapolate."; + + const Sample& pastSample = *(mLatestSamples.end() - 2); + const Sample& presentSample = *(mLatestSamples.end() - 1); + + const nanoseconds delta = presentSample.eventTime - pastSample.eventTime; // The farthest future time to which we can extrapolate. If the given resampleTime exceeds this, // we use this value as the resample time target. - const nanoseconds farthestPrediction = static_cast<nanoseconds>(presentSample.eventTime) + - std::min<nanoseconds>(delta / 2, RESAMPLE_MAX_PREDICTION); + const nanoseconds farthestPrediction = + presentSample.eventTime + std::min<nanoseconds>(delta / 2, RESAMPLE_MAX_PREDICTION); const nanoseconds newResampleTime = (resampleTime > farthestPrediction) ? (farthestPrediction) : (resampleTime); LOG_IF(INFO, debugResampling() && newResampleTime == farthestPrediction) @@ -128,24 +225,36 @@ void LegacyResampler::extrapolate(const nanoseconds resampleTime, MotionEvent& m std::chrono::duration<float, std::milli>(newResampleTime - pastSample.eventTime) / delta; - const PointerCoords resampledCoords = - calculateResampledCoords(pastSample.pointer.coords, presentSample.pointer.coords, - alpha); - motionEvent.addSample(newResampleTime.count(), &resampledCoords, motionEvent.getId()); + std::vector<Pointer> resampledPointers; + for (size_t i = 0; i < presentSample.pointers.size(); ++i) { + const PointerCoords& resampledCoords = + calculateResampledCoords(pastSample.pointers[i].coords, + presentSample.pointers[i].coords, alpha); + resampledPointers.push_back(Pointer{presentSample.pointers[i].properties, resampledCoords}); + } + return Sample{newResampleTime, resampledPointers}; } -void LegacyResampler::resampleMotionEvent(const nanoseconds resampleTime, MotionEvent& motionEvent, +inline void LegacyResampler::addSampleToMotionEvent(const Sample& sample, + MotionEvent& motionEvent) { + motionEvent.addSample(sample.eventTime.count(), sample.asPointerCoords().data(), + motionEvent.getId()); +} + +void LegacyResampler::resampleMotionEvent(nanoseconds resampleTime, MotionEvent& motionEvent, const InputMessage* futureSample) { if (mPreviousDeviceId && *mPreviousDeviceId != motionEvent.getDeviceId()) { mLatestSamples.clear(); } mPreviousDeviceId = motionEvent.getDeviceId(); + updateLatestSamples(motionEvent); - if (futureSample) { - interpolate(resampleTime, motionEvent, *futureSample); - } else { - extrapolate(resampleTime, motionEvent); + + const std::optional<Sample> sample = (futureSample != nullptr) + ? (attemptInterpolation(resampleTime, *futureSample)) + : (attemptExtrapolation(resampleTime)); + if (sample.has_value()) { + addSampleToMotionEvent(*sample, motionEvent); } - LOG_IF(INFO, debugResampling()) << "Not resampled. Not enough data."; } } // namespace android diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 500f7b4d8a..ab117b875e 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -164,3 +164,10 @@ flag { description: "Show touch and pointer indicators when mirroring a single task" bug: "310179437" } + +flag { + name: "include_relative_axis_values_for_captured_touchpads" + namespace: "input" + description: "Include AXIS_RELATIVE_X and AXIS_RELATIVE_Y values when reporting touches from captured touchpads." + bug: "330522990" +} diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp index 135f8b41a2..7ae9a28664 100644 --- a/libs/input/tests/Resampler_test.cpp +++ b/libs/input/tests/Resampler_test.cpp @@ -59,6 +59,9 @@ Pointer::operator PointerCoords() const { struct InputSample { std::chrono::milliseconds eventTime{0}; std::vector<Pointer> pointers{}; + + explicit InputSample(std::chrono::milliseconds eventTime, const std::vector<Pointer>& pointers) + : eventTime{eventTime}, pointers{pointers} {} /** * Converts from InputSample to InputMessage. Enables calling LegacyResampler methods only with * the relevant data for tests. @@ -67,21 +70,18 @@ struct InputSample { }; InputSample::operator InputMessage() const { - InputMessage message; - message.header.type = InputMessage::Type::MOTION; - message.body.motion.pointerCount = pointers.size(); - message.body.motion.eventTime = static_cast<std::chrono::nanoseconds>(eventTime).count(); - message.body.motion.source = AINPUT_SOURCE_CLASS_POINTER; - message.body.motion.downTime = 0; - const uint32_t pointerCount = message.body.motion.pointerCount; - for (uint32_t i = 0; i < pointerCount; ++i) { - message.body.motion.pointers[i].properties.id = pointers[i].id; - message.body.motion.pointers[i].properties.toolType = pointers[i].toolType; - message.body.motion.pointers[i].coords.setAxisValue(AMOTION_EVENT_AXIS_X, pointers[i].x); - message.body.motion.pointers[i].coords.setAxisValue(AMOTION_EVENT_AXIS_Y, pointers[i].y); - message.body.motion.pointers[i].coords.isResampled = pointers[i].isResampled; + InputMessageBuilder messageBuilder = + InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0} + .eventTime(std::chrono::nanoseconds{eventTime}.count()) + .source(AINPUT_SOURCE_TOUCHSCREEN) + .downTime(0); + + for (const Pointer& pointer : pointers) { + messageBuilder.pointer( + PointerBuilder{pointer.id, pointer.toolType}.x(pointer.x).y(pointer.y).isResampled( + pointer.isResampled)); } - return message; + return messageBuilder.build(); } struct InputStream { @@ -132,14 +132,6 @@ protected: std::unique_ptr<Resampler> mResampler; - MotionEvent buildMotionEvent(const int32_t action, const nsecs_t eventTime, - const std::vector<PointerBuilder>& pointers); - - InputMessage createMessage(const uint32_t pointerCount, const nsecs_t eventTime, - const int32_t action, - const std::vector<PointerProperties>& properties, - const std::vector<PointerCoords>& coords); - /** * Checks that beforeCall and afterCall are equal except for the mutated attributes by addSample * member function. @@ -153,42 +145,14 @@ protected: * Asserts the MotionEvent is resampled by checking an increment in history size and that the * resampled coordinates are near the expected ones. */ - void assertMotionEventIsResampledAndCoordsNear(const MotionEvent& original, - const MotionEvent& resampled, - const PointerCoords& expectedCoords); + void assertMotionEventIsResampledAndCoordsNear( + const MotionEvent& original, const MotionEvent& resampled, + const std::vector<PointerCoords>& expectedCoords); void assertMotionEventIsNotResampled(const MotionEvent& original, const MotionEvent& notResampled); }; -MotionEvent ResamplerTest::buildMotionEvent(const int32_t action, const nsecs_t eventTime, - const std::vector<PointerBuilder>& pointerBuilders) { - MotionEventBuilder motionEventBuilder = MotionEventBuilder(action, AINPUT_SOURCE_CLASS_POINTER) - .downTime(0) - .eventTime(eventTime); - for (const PointerBuilder& pointerBuilder : pointerBuilders) { - motionEventBuilder.pointer(pointerBuilder); - } - return motionEventBuilder.build(); -} - -InputMessage ResamplerTest::createMessage(const uint32_t pointerCount, const nsecs_t eventTime, - const int32_t action, - const std::vector<PointerProperties>& properties, - const std::vector<PointerCoords>& coords) { - InputMessage message; - message.header.type = InputMessage::Type::MOTION; - message.body.motion.pointerCount = pointerCount; - message.body.motion.eventTime = eventTime; - message.body.motion.source = AINPUT_SOURCE_CLASS_POINTER; - message.body.motion.downTime = 0; - for (uint32_t i = 0; i < pointerCount; ++i) { - message.body.motion.pointers[i].properties = properties[i]; - message.body.motion.pointers[i].coords = coords[i]; - } - return message; -} - void ResamplerTest::assertMotionEventMetaDataDidNotMutate(const MotionEvent& beforeCall, const MotionEvent& afterCall) { EXPECT_EQ(beforeCall.getDeviceId(), afterCall.getDeviceId()); @@ -207,18 +171,29 @@ void ResamplerTest::assertMotionEventMetaDataDidNotMutate(const MotionEvent& bef EXPECT_EQ(beforeCall.getDisplayId(), afterCall.getDisplayId()); } -void ResamplerTest::assertMotionEventIsResampledAndCoordsNear(const MotionEvent& original, - const MotionEvent& resampled, - const PointerCoords& expectedCoords) { +void ResamplerTest::assertMotionEventIsResampledAndCoordsNear( + const MotionEvent& original, const MotionEvent& resampled, + const std::vector<PointerCoords>& expectedCoords) { assertMotionEventMetaDataDidNotMutate(original, resampled); + const size_t originalSampleSize = original.getHistorySize() + 1; const size_t resampledSampleSize = resampled.getHistorySize() + 1; EXPECT_EQ(originalSampleSize + 1, resampledSampleSize); - const PointerCoords& resampledCoords = - resampled.getSamplePointerCoords()[resampled.getHistorySize()]; - EXPECT_TRUE(resampledCoords.isResampled); - EXPECT_NEAR(expectedCoords.getX(), resampledCoords.getX(), EPSILON); - EXPECT_NEAR(expectedCoords.getY(), resampledCoords.getY(), EPSILON); + + const size_t numPointers = resampled.getPointerCount(); + const size_t beginLatestSample = resampledSampleSize - 1; + for (size_t i = 0; i < numPointers; ++i) { + SCOPED_TRACE(i); + EXPECT_EQ(original.getPointerId(i), resampled.getPointerId(i)); + EXPECT_EQ(original.getToolType(i), resampled.getToolType(i)); + + const PointerCoords& resampledCoords = + resampled.getSamplePointerCoords()[beginLatestSample * numPointers + i]; + + EXPECT_TRUE(resampledCoords.isResampled); + EXPECT_NEAR(expectedCoords[i].getX(), resampledCoords.getX(), EPSILON); + EXPECT_NEAR(expectedCoords[i].getY(), resampledCoords.getY(), EPSILON); + } } void ResamplerTest::assertMotionEventIsNotResampled(const MotionEvent& original, @@ -233,7 +208,7 @@ TEST_F(ResamplerTest, NonResampledAxesArePreserved) { constexpr float TOUCH_MAJOR_VALUE = 1.0f; MotionEvent motionEvent = - InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, + InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; constexpr std::chrono::nanoseconds eventTime{10ms}; @@ -255,34 +230,40 @@ TEST_F(ResamplerTest, NonResampledAxesArePreserved) { EXPECT_EQ(motionEvent.getTouchMajor(0), TOUCH_MAJOR_VALUE); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, - Pointer{.id = 0, - .x = 2.2f, - .y = 2.4f, - .isResampled = true}); + {Pointer{.id = 0, + .x = 2.2f, + .y = 2.4f, + .isResampled = true}}); } TEST_F(ResamplerTest, SinglePointerNotEnoughDataToResample) { MotionEvent motionEvent = - InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, - AMOTION_EVENT_ACTION_MOVE, - .deviceId = 0}; + InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + const MotionEvent originalMotionEvent = motionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, nullptr); + + mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } TEST_F(ResamplerTest, SinglePointerDifferentDeviceIdBetweenMotionEvents) { MotionEvent motionFromFirstDevice = - InputStream{{{4ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}, - {8ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + InputStream{{InputSample{4ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}, + InputSample{8ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE, .deviceId = 0}; + mResampler->resampleMotionEvent(10ms, motionFromFirstDevice, nullptr); + MotionEvent motionFromSecondDevice = - InputStream{{{11ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, + InputStream{{InputSample{11ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE, .deviceId = 1}; const MotionEvent originalMotionEvent = motionFromSecondDevice; + mResampler->resampleMotionEvent(12ms, motionFromSecondDevice, nullptr); // The MotionEvent should not be resampled because the second event came from a different device // than the previous event. @@ -308,28 +289,30 @@ TEST_F(ResamplerTest, SinglePointerDifferentDeviceIdBetweenMotionEvents) { */ TEST_F(ResamplerTest, SinglePointerSingleSampleInterpolation) { MotionEvent motionEvent = - InputStream{{{10ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, + InputStream{{InputSample{10ms, + {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; const InputMessage futureSample = - InputSample{15ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}; + InputSample{15ms, {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}; const MotionEvent originalMotionEvent = motionEvent; mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, - Pointer{.id = 0, - .x = 1.2f, - .y = 1.2f, - .isResampled = true}); + {Pointer{.id = 0, + .x = 1.2f, + .y = 2.4f, + .isResampled = true}}); } TEST_F(ResamplerTest, SinglePointerDeltaTooSmallInterpolation) { MotionEvent motionEvent = - InputStream{{{10ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, + InputStream{{InputSample{10ms, + {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; const InputMessage futureSample = - InputSample{11ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}; + InputSample{11ms, {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}; const MotionEvent originalMotionEvent = motionEvent; @@ -342,25 +325,26 @@ TEST_F(ResamplerTest, SinglePointerDeltaTooSmallInterpolation) { * Tests extrapolation given two MotionEvents with a single sample. */ TEST_F(ResamplerTest, SinglePointerSingleSampleExtrapolation) { - MotionEvent previousMotionEvent = - InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, + MotionEvent firstMotionEvent = + InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; - mResampler->resampleMotionEvent(10ms, previousMotionEvent, nullptr); + mResampler->resampleMotionEvent(9ms, firstMotionEvent, nullptr); - MotionEvent motionEvent = - InputStream{{{10ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}}, + MotionEvent secondMotionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; - const MotionEvent originalMotionEvent = motionEvent; + const MotionEvent originalMotionEvent = secondMotionEvent; - mResampler->resampleMotionEvent(11ms, motionEvent, nullptr); + mResampler->resampleMotionEvent(11ms, secondMotionEvent, nullptr); - assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, - Pointer{.id = 0, - .x = 1.0f, - .y = 1.0f, - .isResampled = true}); + assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent, + {Pointer{.id = 0, + .x = 2.2f, + .y = 4.4f, + .isResampled = true}}); // Integrity of the whole motionEvent // History size should increment by 1 // Check if the resampled value is the last one @@ -370,27 +354,30 @@ TEST_F(ResamplerTest, SinglePointerSingleSampleExtrapolation) { TEST_F(ResamplerTest, SinglePointerMultipleSampleInterpolation) { MotionEvent motionEvent = - InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}, - {10ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}, + InputSample{10ms, + {{.id = 0, .x = 2.0f, .y = 3.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; + const InputMessage futureSample = - InputSample{15ms, {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}}; + InputSample{15ms, {{.id = 0, .x = 3.0f, .y = 5.0f, .isResampled = false}}}; const MotionEvent originalMotionEvent = motionEvent; mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, - Pointer{.id = 0, - .x = 2.2f, - .y = 2.2f, - .isResampled = true}); + {Pointer{.id = 0, + .x = 2.2f, + .y = 3.4f, + .isResampled = true}}); } TEST_F(ResamplerTest, SinglePointerMultipleSampleExtrapolation) { MotionEvent motionEvent = - InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}, - {10ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}, + InputSample{10ms, + {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; const MotionEvent originalMotionEvent = motionEvent; @@ -398,16 +385,17 @@ TEST_F(ResamplerTest, SinglePointerMultipleSampleExtrapolation) { mResampler->resampleMotionEvent(11ms, motionEvent, nullptr); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, - Pointer{.id = 0, - .x = 2.2f, - .y = 2.2f, - .isResampled = true}); + {Pointer{.id = 0, + .x = 2.2f, + .y = 4.4f, + .isResampled = true}}); } TEST_F(ResamplerTest, SinglePointerDeltaTooSmallExtrapolation) { MotionEvent motionEvent = - InputStream{{{9ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}, - {10ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + InputStream{{InputSample{9ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}, + InputSample{10ms, + {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; const MotionEvent originalMotionEvent = motionEvent; @@ -419,8 +407,9 @@ TEST_F(ResamplerTest, SinglePointerDeltaTooSmallExtrapolation) { TEST_F(ResamplerTest, SinglePointerDeltaTooLargeExtrapolation) { MotionEvent motionEvent = - InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}, - {26ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}, + InputSample{26ms, + {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; const MotionEvent originalMotionEvent = motionEvent; @@ -432,8 +421,9 @@ TEST_F(ResamplerTest, SinglePointerDeltaTooLargeExtrapolation) { TEST_F(ResamplerTest, SinglePointerResampleTimeTooFarExtrapolation) { MotionEvent motionEvent = - InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}, - {25ms, {{.id = 0, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + InputStream{{InputSample{5ms, {{.id = 0, .x = 1.0f, .y = 2.0f, .isResampled = false}}}, + InputSample{25ms, + {{.id = 0, .x = 2.0f, .y = 4.0f, .isResampled = false}}}}, AMOTION_EVENT_ACTION_MOVE}; const MotionEvent originalMotionEvent = motionEvent; @@ -441,9 +431,424 @@ TEST_F(ResamplerTest, SinglePointerResampleTimeTooFarExtrapolation) { mResampler->resampleMotionEvent(43ms, motionEvent, nullptr); assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, - Pointer{.id = 0, - .x = 2.4f, - .y = 2.4f, - .isResampled = true}); + {Pointer{.id = 0, + .x = 2.4f, + .y = 4.8f, + .isResampled = true}}); +} + +TEST_F(ResamplerTest, MultiplePointerSingleSampleInterpolation) { + MotionEvent motionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage futureSample = + InputSample{15ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + + assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, + {Pointer{.x = 2.2f, .y = 2.2f, .isResampled = true}, + Pointer{.x = 3.2f, .y = 3.2f, .isResampled = true}}); +} + +TEST_F(ResamplerTest, MultiplePointerSingleSampleExtrapolation) { + MotionEvent firstMotionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr); + + MotionEvent secondMotionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent originalMotionEvent = secondMotionEvent; + + mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, secondMotionEvent, + {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, + Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}}); +} + +TEST_F(ResamplerTest, MultiplePointerMultipleSampleInterpolation) { + MotionEvent motionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}, + InputSample{10ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + const InputMessage futureSample = + InputSample{15ms, + {{.id = 0, .x = 5.0f, .y = 5.0f, .isResampled = false}, + {.id = 1, .x = 6.0f, .y = 6.0f, .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + + assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, + {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, + Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}}); +} + +TEST_F(ResamplerTest, MultiplePointerMultipleSampleExtrapolation) { + MotionEvent motionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}, + InputSample{10ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, + {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, + Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}}); +} + +TEST_F(ResamplerTest, MultiplePointerIncreaseNumPointersInterpolation) { + MotionEvent motionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage futureSample = + InputSample{15ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + + assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent, + {Pointer{.x = 1.4f, .y = 1.4f, .isResampled = true}, + Pointer{.x = 2.4f, .y = 2.4f, .isResampled = true}}); + + MotionEvent secondMotionEvent = + InputStream{{InputSample{25ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage secondFutureSample = + InputSample{30ms, + {{.id = 0, .x = 5.0f, .y = 5.0f, .isResampled = false}, + {.id = 1, .x = 6.0f, .y = 6.0f, .isResampled = false}, + {.id = 2, .x = 7.0f, .y = 7.0f, .isResampled = false}}}; + + const MotionEvent originalSecondMotionEvent = secondMotionEvent; + + mResampler->resampleMotionEvent(27ms, secondMotionEvent, &secondFutureSample); + + assertMotionEventIsResampledAndCoordsNear(originalSecondMotionEvent, secondMotionEvent, + {Pointer{.x = 3.8f, .y = 3.8f, .isResampled = true}, + Pointer{.x = 4.8f, .y = 4.8f, .isResampled = true}, + Pointer{.x = 5.8f, .y = 5.8f, .isResampled = true}}); +} + +TEST_F(ResamplerTest, MultiplePointerIncreaseNumPointersExtrapolation) { + MotionEvent firstMotionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr); + + MotionEvent secondMotionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent secondOriginalMotionEvent = secondMotionEvent; + + mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerDecreaseNumPointersInterpolation) { + MotionEvent motionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 2, .x = 5.0f, .y = 5.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage futureSample = + InputSample{15ms, + {{.id = 0, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 1, .x = 5.0f, .y = 5.0f, .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + + assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerDecreaseNumPointersExtrapolation) { + MotionEvent firstMotionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}, + {.id = 2, .x = 3.0f, .y = 3.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr); + + MotionEvent secondMotionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}, + {.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent secondOriginalMotionEvent = secondMotionEvent; + + mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsResampledAndCoordsNear(secondOriginalMotionEvent, secondMotionEvent, + {Pointer{.x = 3.4f, .y = 3.4f, .isResampled = true}, + Pointer{.x = 4.4f, .y = 4.4f, .isResampled = true}}); +} + +TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderInterpolation) { + MotionEvent motionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage futureSample = + InputSample{15ms, + {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + + assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerDifferentIdOrderExtrapolation) { + MotionEvent firstMotionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr); + + MotionEvent secondMotionEvent = + InputStream{{InputSample{10ms, + {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 0, .x = 3.0f, .y = 3.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent secondOriginalMotionEvent = secondMotionEvent; + + mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerDifferentIdsInterpolation) { + MotionEvent motionEvent = + InputStream{{InputSample{10ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage futureSample = + InputSample{15ms, + {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 2, .x = 3.0f, .y = 3.0f, .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + + assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerDifferentIdsExtrapolation) { + MotionEvent firstMotionEvent = + InputStream{{InputSample{5ms, + {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}, + {.id = 1, .x = 2.0f, .y = 2.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr); + + MotionEvent secondMotionEvent = + InputStream{{InputSample{10ms, + {{.id = 1, .x = 4.0f, .y = 4.0f, .isResampled = false}, + {.id = 2, .x = 3.0f, .y = 3.0f, .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent secondOriginalMotionEvent = secondMotionEvent; + + mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerDifferentToolTypeInterpolation) { + MotionEvent motionEvent = InputStream{{InputSample{10ms, + {{.id = 0, + .toolType = ToolType::FINGER, + .x = 1.0f, + .y = 1.0f, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::FINGER, + .x = 2.0f, + .y = 2.0f, + .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage futureSample = InputSample{15ms, + {{.id = 0, + .toolType = ToolType::FINGER, + .x = 3.0, + .y = 3.0, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::STYLUS, + .x = 4.0, + .y = 4.0, + .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample); + + assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerDifferentToolTypeExtrapolation) { + MotionEvent firstMotionEvent = InputStream{{InputSample{5ms, + {{.id = 0, + .toolType = ToolType::FINGER, + .x = 1.0f, + .y = 1.0f, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::FINGER, + .x = 2.0f, + .y = 2.0f, + .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + mResampler->resampleMotionEvent(9ms, firstMotionEvent, /*futureSample=*/nullptr); + + MotionEvent secondMotionEvent = InputStream{{InputSample{10ms, + {{.id = 0, + .toolType = ToolType::FINGER, + .x = 1.0f, + .y = 1.0f, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::STYLUS, + .x = 2.0f, + .y = 2.0f, + .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent secondOriginalMotionEvent = secondMotionEvent; + + mResampler->resampleMotionEvent(11ms, secondMotionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsNotResampled(secondOriginalMotionEvent, secondMotionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerShouldNotResampleToolTypeInterpolation) { + MotionEvent motionEvent = InputStream{{InputSample{10ms, + {{.id = 0, + .toolType = ToolType::PALM, + .x = 1.0f, + .y = 1.0f, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::PALM, + .x = 2.0f, + .y = 2.0f, + .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const InputMessage futureSample = InputSample{15ms, + {{.id = 0, + .toolType = ToolType::PALM, + .x = 3.0, + .y = 3.0, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::PALM, + .x = 4.0, + .y = 4.0, + .isResampled = false}}}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); +} + +TEST_F(ResamplerTest, MultiplePointerShouldNotResampleToolTypeExtrapolation) { + MotionEvent motionEvent = InputStream{{InputSample{5ms, + {{.id = 0, + .toolType = ToolType::PALM, + .x = 1.0f, + .y = 1.0f, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::PALM, + .x = 2.0f, + .y = 2.0f, + .isResampled = false}}}, + InputSample{10ms, + {{.id = 0, + .toolType = ToolType::PALM, + .x = 3.0f, + .y = 3.0f, + .isResampled = false}, + {.id = 1, + .toolType = ToolType::PALM, + .x = 4.0f, + .y = 4.0f, + .isResampled = false}}}}, + AMOTION_EVENT_ACTION_MOVE}; + + const MotionEvent originalMotionEvent = motionEvent; + + mResampler->resampleMotionEvent(11ms, motionEvent, /*futureSample=*/nullptr); + + assertMotionEventIsNotResampled(originalMotionEvent, motionEvent); } } // namespace android diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h index 099f47dbe1..f1453bd64d 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -98,11 +98,25 @@ public: * is created in a detached state, and attachToContext must be called before * calls to updateTexImage. */ +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + SurfaceTexture(uint32_t tex, uint32_t textureTarget, bool useFenceSync, bool isControlledByApp); + + SurfaceTexture(uint32_t textureTarget, bool useFenceSync, bool isControlledByApp); + + SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t textureTarget, + bool useFenceSync, bool isControlledByApp) + __attribute((deprecated("Prefer ctors that create their own surface and consumer."))); + + SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget, bool useFenceSync, + bool isControlledByApp) + __attribute((deprecated("Prefer ctors that create their own surface and consumer."))); +#else SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t textureTarget, bool useFenceSync, bool isControlledByApp); SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget, bool useFenceSync, bool isControlledByApp); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) /** * updateTexImage acquires the most recently queued buffer, and sets the @@ -499,6 +513,8 @@ protected: friend class EGLConsumer; private: + void initialize(); + // Proxy listener to avoid having SurfaceTexture directly implement FrameAvailableListener as it // is extending ConsumerBase which also implements FrameAvailableListener. class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener { diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index 3a09204878..ce232cc4c7 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -35,6 +35,49 @@ namespace android { static const mat4 mtxIdentity; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +SurfaceTexture::SurfaceTexture(uint32_t tex, uint32_t texTarget, bool useFenceSync, + bool isControlledByApp) + : ConsumerBase(isControlledByApp), + mCurrentCrop(Rect::EMPTY_RECT), + mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mCurrentFence(Fence::NO_FENCE), + mCurrentTimestamp(0), + mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentFrameNumber(0), + mDefaultWidth(1), + mDefaultHeight(1), + mFilteringEnabled(true), + mTexName(tex), + mUseFenceSync(useFenceSync), + mTexTarget(texTarget), + mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), + mOpMode(OpMode::attachedToGL) { + initialize(); +} + +SurfaceTexture::SurfaceTexture(uint32_t texTarget, bool useFenceSync, bool isControlledByApp) + : ConsumerBase(isControlledByApp), + mCurrentCrop(Rect::EMPTY_RECT), + mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mCurrentFence(Fence::NO_FENCE), + mCurrentTimestamp(0), + mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentFrameNumber(0), + mDefaultWidth(1), + mDefaultHeight(1), + mFilteringEnabled(true), + mTexName(0), + mUseFenceSync(useFenceSync), + mTexTarget(texTarget), + mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), + mOpMode(OpMode::detached) { + initialize(); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), @@ -53,11 +96,7 @@ SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t te mTexTarget(texTarget), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mOpMode(OpMode::attachedToGL) { - SFT_LOGV("SurfaceTexture"); - - memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); - - mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); + initialize(); } SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, @@ -78,11 +117,7 @@ SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t te mTexTarget(texTarget), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mOpMode(OpMode::detached) { - SFT_LOGV("SurfaceTexture"); - - memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); - - mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); + initialize(); } status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) { @@ -531,4 +566,12 @@ void SurfaceTexture::onSetFrameRate(float frameRate, int8_t compatibility, } #endif +void SurfaceTexture::initialize() { + SFT_LOGV("SurfaceTexture"); + + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); + + mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); +} + } // namespace android diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 6cf8291da2..937ff02241 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -50,9 +50,14 @@ protected: const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + mItemConsumer = new BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN); + mWindow = new TestableSurface(mItemConsumer->getSurface()->getIGraphicBufferProducer()); +#else BufferQueue::createBufferQueue(&mProducer, &mConsumer); mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN); mWindow = new TestableSurface(mProducer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU); EXPECT_EQ(0, success); } @@ -64,10 +69,12 @@ protected: const int success = native_window_api_disconnect(mWindow.get(), NATIVE_WINDOW_API_CPU); EXPECT_EQ(0, success); } + +#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) sp<IGraphicBufferProducer> mProducer; sp<IGraphicBufferConsumer> mConsumer; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) sp<BufferItemConsumer> mItemConsumer; - sp<TestableSurface> mWindow; }; diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp index 1dbcc29190..4164c4b4c9 100644 --- a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp +++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp @@ -19,6 +19,7 @@ #include <SkRuntimeEffect.h> #include <SkStream.h> #include <SkString.h> +#include <com_android_graphics_libgui_flags.h> #include "log/log_main.h" namespace android::renderengine::skia { @@ -56,25 +57,33 @@ static const SkString edgeShader = SkString(R"( } )"); +EdgeExtensionShaderFactory::EdgeExtensionShaderFactory() { + if (!com::android::graphics::libgui::flags::edge_extension_shader()) { + return; + } + mResult = std::make_unique<SkRuntimeEffect::Result>(SkRuntimeEffect::MakeForShader(edgeShader)); + LOG_ALWAYS_FATAL_IF(!mResult->errorText.isEmpty(), + "EdgeExtensionShaderFactory compilation " + "failed with an unexpected error: %s", + mResult->errorText.c_str()); +} + sk_sp<SkShader> EdgeExtensionShaderFactory::createSkShader(const sk_sp<SkShader>& inputShader, const LayerSettings& layer, - const SkRect& imageBounds) { - if (mBuilder == nullptr) { - const static SkRuntimeEffect::Result instance = SkRuntimeEffect::MakeForShader(edgeShader); - if (!instance.errorText.isEmpty()) { - ALOGE("EdgeExtensionShaderFactory terminated with an error: %s", - instance.errorText.c_str()); - return nullptr; - } - mBuilder = std::make_unique<SkRuntimeShaderBuilder>(instance.effect); - } - mBuilder->child("uContentTexture") = inputShader; + const SkRect& imageBounds) const { + LOG_ALWAYS_FATAL_IF(mResult == nullptr, + "EdgeExtensionShaderFactory did not initialize mResult. " + "This means that we unexpectedly applied the edge extension shader"); + + SkRuntimeShaderBuilder builder = SkRuntimeShaderBuilder(mResult->effect); + + builder.child("uContentTexture") = inputShader; if (imageBounds.isEmpty()) { - mBuilder->uniform("uImgSize") = SkPoint{layer.geometry.boundaries.getWidth(), - layer.geometry.boundaries.getHeight()}; + builder.uniform("uImgSize") = SkPoint{layer.geometry.boundaries.getWidth(), + layer.geometry.boundaries.getHeight()}; } else { - mBuilder->uniform("uImgSize") = SkPoint{imageBounds.width(), imageBounds.height()}; + builder.uniform("uImgSize") = SkPoint{imageBounds.width(), imageBounds.height()}; } - return mBuilder->makeShader(); + return builder.makeShader(); } } // namespace android::renderengine::skia
\ No newline at end of file diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h index b0a8a9357e..17c6b9139f 100644 --- a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h +++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h @@ -33,10 +33,12 @@ namespace android::renderengine::skia { */ class EdgeExtensionShaderFactory { public: + EdgeExtensionShaderFactory(); + sk_sp<SkShader> createSkShader(const sk_sp<SkShader>& inputShader, const LayerSettings& layer, - const SkRect& imageBounds); + const SkRect& imageBounds) const; private: - std::unique_ptr<SkRuntimeShaderBuilder> mBuilder; + std::unique_ptr<const SkRuntimeEffect::Result> mResult; }; } // namespace android::renderengine::skia diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h index 9aae145c04..a75ba37d2c 100644 --- a/libs/ui/include/ui/Fence.h +++ b/libs/ui/include/ui/Fence.h @@ -156,6 +156,6 @@ private: base::unique_fd mFenceFd; }; -}; // namespace android +} // namespace android #endif // ANDROID_FENCE_H diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 652d8ba709..936bf8f862 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -297,6 +297,6 @@ private: mDeathCallbacks; }; -}; // namespace android +} // namespace android #endif // ANDROID_GRAPHIC_BUFFER_H diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h index bbb2d77058..97ed05af6d 100644 --- a/libs/ui/include/ui/GraphicBufferAllocator.h +++ b/libs/ui/include/ui/GraphicBufferAllocator.h @@ -137,6 +137,6 @@ protected: }; // --------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif // ANDROID_BUFFER_ALLOCATOR_H diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h index 9da1447aed..91aabe9f12 100644 --- a/libs/ui/include/ui/GraphicBufferMapper.h +++ b/libs/ui/include/ui/GraphicBufferMapper.h @@ -188,7 +188,7 @@ private: // --------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif // ANDROID_UI_BUFFER_MAPPER_H diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h index cf5c2e8c12..1f20787bb0 100644 --- a/libs/ui/include/ui/PixelFormat.h +++ b/libs/ui/include/ui/PixelFormat.h @@ -72,6 +72,6 @@ typedef int32_t PixelFormat; uint32_t bytesPerPixel(PixelFormat format); -}; // namespace android +} // namespace android #endif // UI_PIXELFORMAT_H diff --git a/libs/ui/include/ui/Point.h b/libs/ui/include/ui/Point.h index d050ede02d..97a54beca7 100644 --- a/libs/ui/include/ui/Point.h +++ b/libs/ui/include/ui/Point.h @@ -83,6 +83,6 @@ public: ANDROID_BASIC_TYPES_TRAITS(Point) -}; // namespace android +} // namespace android #endif // ANDROID_UI_POINT diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h index 9e24a077ff..2eb9330cc9 100644 --- a/libs/ui/include/ui/Rect.h +++ b/libs/ui/include/ui/Rect.h @@ -233,7 +233,7 @@ void PrintTo(const Rect& rect, ::std::ostream* os); ANDROID_BASIC_TYPES_TRAITS(Rect) -}; // namespace android +} // namespace android namespace std { template <> diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h index 927c334c85..d1b38f3bd3 100644 --- a/libs/ui/include/ui/Region.h +++ b/libs/ui/include/ui/Region.h @@ -233,7 +233,7 @@ static inline void PrintTo(const Region& region, ::std::ostream* os) { } // --------------------------------------------------------------------------- -}; // namespace android +} // namespace android namespace std { template <> diff --git a/libs/vibrator/ExternalVibrationUtils.cpp b/libs/vibrator/ExternalVibrationUtils.cpp index 54afb71a97..ca13afcbaf 100644 --- a/libs/vibrator/ExternalVibrationUtils.cpp +++ b/libs/vibrator/ExternalVibrationUtils.cpp @@ -167,7 +167,7 @@ void applyHapticScale(float* buffer, size_t length, HapticScale scale) { } } - if (adaptiveScaleFactor != 1.0f) { + if (adaptiveScaleFactor >= 0 && adaptiveScaleFactor != 1.0f) { buffer[i] *= adaptiveScaleFactor; } } diff --git a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h index 322a2ac899..f0760fda1b 100644 --- a/libs/vibrator/include/vibrator/ExternalVibrationUtils.h +++ b/libs/vibrator/include/vibrator/ExternalVibrationUtils.h @@ -57,7 +57,9 @@ bool isScaleNone() const { return (mLevel == HapticLevel::NONE || mScaleFactor == 1.0f) && mAdaptiveScaleFactor == 1.0f; } -bool isScaleMute() const { return mLevel == HapticLevel::MUTE || mScaleFactor == 0; } +bool isScaleMute() const { + return mLevel == HapticLevel::MUTE || mScaleFactor == 0 || mAdaptiveScaleFactor == 0; +} std::string toString() const { std::ostringstream os; diff --git a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp index 7adc9c33de..9369f80da3 100644 --- a/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp +++ b/libs/vibrator/tests/ExternalVibrationUtilsTest.cpp @@ -188,9 +188,19 @@ TEST_F_WITH_FLAGS( } TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, TestScaleV2ToScaleFactorUndefinedUsesHapticLevel, + // Value of fix_audio_coupled_haptics_scaling is not important, should work with either + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + constexpr float adaptiveScaleNone = 1.0f; + float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8f, -0.38f}; + scaleBuffer(HapticScale(HapticLevel::VERY_HIGH, -1.0f /* scaleFactor */, adaptiveScaleNone)); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( ExternalVibrationUtilsTest, TestScaleV2ToScaleFactorIgnoresLevel, - // Value of fix_audio_coupled_haptics_scaling is not important, should work with either - REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + // Value of fix_audio_coupled_haptics_scaling is not important, should work with either + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { constexpr float adaptiveScaleNone = 1.0f; float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 1, -1, 1, -0.55f }; @@ -210,9 +220,23 @@ TEST_F_WITH_FLAGS( EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } +TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorUndefinedIsIgnoredLegacyScale, + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling), + ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.79f, -0.39f}; + scaleBuffer(HapticLevel::VERY_HIGH, -1.0f /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorAppliedAfterLegacyScale, REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling), ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + // Adaptive scale mutes vibration + float expectedMuted[TEST_BUFFER_LENGTH]; + std::fill(std::begin(expectedMuted), std::end(expectedMuted), 0); + scaleBuffer(HapticLevel::VERY_HIGH, 0.0f /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + // Haptic level scale up then adaptive scale down float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.13f }; scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */); @@ -234,9 +258,23 @@ TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorAppliedAfte EXPECT_FLOATS_NEARLY_EQ(expectedVeryLow, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); } +TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorUndefinedIgnoredFixedScale, + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)), + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.79f, -0.39f}; + scaleBuffer(HapticLevel::VERY_HIGH, -1.0f /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorAppliedAfterFixedScale, REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, fix_audio_coupled_haptics_scaling)), REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + // Adaptive scale mutes vibration + float expectedMuted[TEST_BUFFER_LENGTH]; + std::fill(std::begin(expectedMuted), std::end(expectedMuted), 0); + scaleBuffer(HapticLevel::VERY_HIGH, 0.0f /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + // Haptic level scale up then adaptive scale down float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.16f, -0.07f }; scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */); @@ -259,9 +297,24 @@ TEST_F_WITH_FLAGS(ExternalVibrationUtilsTest, TestAdaptiveScaleFactorAppliedAfte } TEST_F_WITH_FLAGS( + ExternalVibrationUtilsTest, TestAdaptiveScaleFactorUndefinedIgnoredScaleV2, + // Value of fix_audio_coupled_haptics_scaling is not important, should work with either + REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + float expectedVeryHigh[TEST_BUFFER_LENGTH] = {1, -1, 0.8f, -0.38f}; + scaleBuffer(HapticLevel::VERY_HIGH, -1.0f /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedVeryHigh, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); +} + +TEST_F_WITH_FLAGS( ExternalVibrationUtilsTest, TestAdaptiveScaleFactorAppliedAfterScaleV2, // Value of fix_audio_coupled_haptics_scaling is not important, should work with either REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(FLAG_NS, haptics_scale_v2_enabled))) { + // Adaptive scale mutes vibration + float expectedMuted[TEST_BUFFER_LENGTH]; + std::fill(std::begin(expectedMuted), std::end(expectedMuted), 0); + scaleBuffer(HapticLevel::VERY_HIGH, 0.0f /* adaptiveScaleFactor */); + EXPECT_FLOATS_NEARLY_EQ(expectedMuted, mBuffer, TEST_BUFFER_LENGTH, TEST_TOLERANCE); + // Haptic level scale up then adaptive scale down float expectedVeryHigh[TEST_BUFFER_LENGTH] = { 0.2, -0.2, 0.15f, -0.07f }; scaleBuffer(HapticLevel::VERY_HIGH, 0.2f /* adaptiveScaleFactor */); diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp index 3ef5049230..da1aae2acb 100644 --- a/services/audiomanager/IAudioManager.cpp +++ b/services/audiomanager/IAudioManager.cpp @@ -152,6 +152,12 @@ public: data.writeNullableParcelable(extras); return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY); } + + virtual status_t permissionUpdateBarrier() { + Parcel data, reply; + data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor()); + return remote()->transact(PERMISSION_UPDATE_BARRIER, data, &reply, 0); + } }; IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService"); diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp index 1a744abc6d..00161e6f4c 100644 --- a/services/gpuservice/gpuwork/GpuWork.cpp +++ b/services/gpuservice/gpuwork/GpuWork.cpp @@ -118,6 +118,9 @@ GpuWork::~GpuWork() { } void GpuWork::initialize() { + // Workaround b/347947040 by allowing time for statsd / bpf setup. + std::this_thread::sleep_for(std::chrono::seconds(30)); + // Make sure BPF programs are loaded. bpf::waitForProgsLoaded(); diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 625599a775..397fedac4c 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -511,8 +511,9 @@ void PointerChoreographer::dump(std::string& dump) { std::scoped_lock _l(mLock); dump += "PointerChoreographer:\n"; - dump += StringPrintf("show touches: %s\n", mShowTouchesEnabled ? "true" : "false"); - dump += StringPrintf("stylus pointer icon enabled: %s\n", + dump += StringPrintf(INDENT "Show Touches Enabled: %s\n", + mShowTouchesEnabled ? "true" : "false"); + dump += StringPrintf(INDENT "Stylus PointerIcon Enabled: %s\n", mStylusPointerIconEnabled ? "true" : "false"); dump += INDENT "MousePointerControllers:\n"; diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 42a03c10ca..7bec94eea1 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -34,7 +34,9 @@ #include <vector> #include "PointerControllerInterface.h" +#include "TouchpadHardwareState.h" #include "VibrationElement.h" +#include "include/gestures.h" // Maximum supported size of a vibration pattern. // Must be at least 2. @@ -227,6 +229,9 @@ struct InputReaderConfiguration { // True to enable tap dragging on touchpads. bool touchpadTapDraggingEnabled; + // True if hardware state update notifications should be sent to the policy. + bool shouldNotifyTouchpadHardwareState; + // True to enable a zone on the right-hand side of touchpads where clicks will be turned into // context (a.k.a. "right") clicks. bool touchpadRightClickZoneEnabled; @@ -268,6 +273,7 @@ struct InputReaderConfiguration { touchpadNaturalScrollingEnabled(true), touchpadTapToClickEnabled(true), touchpadTapDraggingEnabled(false), + shouldNotifyTouchpadHardwareState(false), touchpadRightClickZoneEnabled(false), stylusButtonMotionEventsEnabled(true), stylusPointerIconEnabled(false) {} @@ -363,6 +369,8 @@ public: virtual std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) = 0; + virtual std::optional<HardwareProperties> getTouchpadHardwareProperties(int32_t deviceId) = 0; + /* Return true if the device can send input events to the specified display. */ virtual bool canDispatchToDisplay(int32_t deviceId, ui::LogicalDisplayId displayId) = 0; @@ -454,6 +462,10 @@ public: */ virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) = 0; + /* Sends the hardware state of a connected touchpad */ + virtual void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, + int32_t deviceId) = 0; + /* Gets the keyboard layout for a particular input device. */ virtual std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier, diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 2daf195757..70f024ea96 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -725,6 +725,15 @@ size_t InputDevice::getMapperCount() { return count; } +std::optional<HardwareProperties> InputDevice::getTouchpadHardwareProperties() { + std::optional<HardwareProperties> result = first_in_mappers<HardwareProperties>( + [](InputMapper& mapper) -> std::optional<HardwareProperties> { + return mapper.getTouchpadHardwareProperties(); + }); + + return result; +} + void InputDevice::updateLedState(bool reset) { for_each_mapper([reset](InputMapper& mapper) { mapper.updateLedState(reset); }); } diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index f0e53b5464..a5b12490a3 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -33,6 +33,7 @@ #include <utils/Thread.h> #include "InputDevice.h" +#include "include/gestures.h" using android::base::StringPrintf; @@ -817,6 +818,18 @@ std::vector<InputDeviceSensorInfo> InputReader::getSensors(int32_t deviceId) { return device->getDeviceInfo().getSensors(); } +std::optional<HardwareProperties> InputReader::getTouchpadHardwareProperties(int32_t deviceId) { + std::scoped_lock _l(mLock); + + InputDevice* device = findInputDeviceLocked(deviceId); + + if (device == nullptr) { + return {}; + } + + return device->getTouchpadHardwareProperties(); +} + bool InputReader::setLightColor(int32_t deviceId, int32_t lightId, int32_t color) { std::scoped_lock _l(mLock); diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 93785f670d..021978dee7 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -141,6 +141,8 @@ public: size_t getMapperCount(); + std::optional<HardwareProperties> getTouchpadHardwareProperties(); + // construct and add a mapper to the input device template <class T, typename... Args> T& addMapper(int32_t eventHubId, Args... args) { diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 4f60a8a50f..2cc0a00496 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -104,6 +104,8 @@ public: std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) override; + std::optional<HardwareProperties> getTouchpadHardwareProperties(int32_t deviceId) override; + bool setLightColor(int32_t deviceId, int32_t lightId, int32_t color) override; bool setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) override; diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp index c8e7790c86..dd46bbc543 100644 --- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp +++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp @@ -20,14 +20,19 @@ #include <sstream> #include <android-base/stringprintf.h> +#include <com_android_input_flags.h> #include <input/PrintTools.h> #include <linux/input-event-codes.h> #include <log/log_main.h> +namespace input_flags = com::android::input::flags; + namespace android { namespace { +static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD; + int32_t actionWithIndex(int32_t action, int32_t index) { return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } @@ -43,6 +48,12 @@ size_t firstUnmarkedBit(T set) { return i; } +void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis, + RawAbsoluteAxisInfo& evdevAxis) { + deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue, + evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution); +} + } // namespace CapturedTouchpadEventConverter::CapturedTouchpadEventConverter( @@ -108,8 +119,15 @@ std::string CapturedTouchpadEventConverter::dump() const { } void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const { - tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X); - tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X, + AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X); + tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y, + AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y); + } else { + tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X); + tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y); + } tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR); tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR); tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR); @@ -135,8 +153,23 @@ void CapturedTouchpadEventConverter::tryAddRawMotionRange(InputDeviceInfo& devic int32_t evdevAxis) const { std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis); if (info) { - deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat, - info->fuzz, info->resolution); + addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info); + } +} + +void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, + int32_t androidAxis, + int32_t androidRelativeAxis, + int32_t evdevAxis) const { + std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis); + if (axisInfo) { + addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo); + + // The largest movement we could possibly report on a relative axis is from the minimum to + // the maximum (or vice versa) of the absolute axis. + float range = axisInfo->maxValue - axisInfo->minValue; + deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat, + axisInfo->fuzz, axisInfo->resolution); } } @@ -163,7 +196,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t std::list<NotifyArgs> out; std::vector<PointerCoords> coords; std::vector<PointerProperties> properties; - std::map<size_t, size_t> coordsIndexForSlotNumber; + std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber; // For all the touches that were already down, send a MOVE event with their updated coordinates. // A convention of the MotionEvent API is that pointer coordinates in UP events match the @@ -175,11 +208,19 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t // to stay perfectly still between frames, and if it does the worst that can happen is // an extra MOVE event, so it's not worth the overhead of checking for changes. coordsIndexForSlotNumber[slotNumber] = coords.size(); - coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber))); + coords.push_back(makePointerCoordsForSlot(slotNumber)); properties.push_back({.id = pointerId, .toolType = ToolType::FINGER}); } out.push_back( makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties)); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + // For any further events we send from this sync, the pointers won't have moved relative + // to the positions we just reported in this MOVE event, so zero out the relative axes. + for (PointerCoords& pointer : coords) { + pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); + pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); + } + } } std::vector<size_t> upSlots, downSlots; @@ -234,6 +275,9 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0)); freePointerIdForSlot(slotNumber); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + mPreviousCoordsForSlotNumber.erase(slotNumber); + } coords.erase(coords.begin() + indexToRemove); properties.erase(properties.begin() + indexToRemove); // Now that we've removed some coords and properties, we might have to update the slot @@ -254,7 +298,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex); coordsIndexForSlotNumber[slotNumber] = coordsIndex; - coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber))); + coords.push_back(makePointerCoordsForSlot(slotNumber)); properties.push_back( {.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER}); @@ -286,12 +330,22 @@ NotifyMotionArgs CapturedTouchpadEventConverter::makeMotionArgs( AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{}); } -PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot( - const MultiTouchMotionAccumulator::Slot& slot) const { +PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) { + const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber); PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX()); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY()); + if (input_flags::include_relative_axis_values_for_captured_touchpads()) { + if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber); + it != mPreviousCoordsForSlotNumber.end()) { + auto [oldX, oldY] = it->second; + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX); + coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY); + } + mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY()); + } + coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor()); coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor()); coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor()); diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h index 9b6df7a222..d6c0708f4a 100644 --- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h +++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.h @@ -21,6 +21,7 @@ #include <map> #include <set> #include <string> +#include <utility> #include <vector> #include <android/input.h> @@ -49,12 +50,14 @@ public: private: void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis, int32_t evdevAxis) const; + void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis, + int32_t androidRelativeAxis, int32_t evdevAxis) const; [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime); [[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action, const std::vector<PointerCoords>& coords, const std::vector<PointerProperties>& properties, int32_t actionButton = 0, int32_t flags = 0); - PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const; + PointerCoords makePointerCoordsForSlot(size_t slotNumber); int32_t allocatePointerIdToSlot(size_t slotNumber); void freePointerIdForSlot(size_t slotNumber); @@ -76,8 +79,7 @@ private: std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse; std::map<size_t, int32_t> mPointerIdForSlotNumber; - - static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD; + std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp index c44c48c0bf..627df7fb5b 100644 --- a/services/inputflinger/reader/mapper/InputMapper.cpp +++ b/services/inputflinger/reader/mapper/InputMapper.cpp @@ -140,4 +140,7 @@ void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) { dump += StringPrintf(INDENT4 "Tool Type: %s\n", ftl::enum_string(state.toolType).c_str()); } +std::optional<HardwareProperties> InputMapper::getTouchpadHardwareProperties() { + return std::nullopt; +} } // namespace android diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index e5afcc798e..75cc4bb410 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -122,6 +122,8 @@ public: virtual std::optional<ui::LogicalDisplayId> getAssociatedDisplayId() { return std::nullopt; } virtual void updateLedState(bool reset) {} + virtual std::optional<HardwareProperties> getTouchpadHardwareProperties(); + protected: InputDeviceContext& mDeviceContext; diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index 5c5fd3fb5f..dbc28721d1 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -36,6 +36,7 @@ #include <log/log_main.h> #include <stats_pull_atom_callback.h> #include <statslog.h> +#include "InputReaderBase.h" #include "TouchCursorInputMapperCommon.h" #include "TouchpadInputMapper.h" #include "gestures/HardwareProperties.h" @@ -251,7 +252,8 @@ TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext, } mGestureInterpreter->Initialize(GESTURES_DEVCLASS_TOUCHPAD); - mGestureInterpreter->SetHardwareProperties(createHardwareProperties(deviceContext)); + mHardwareProperties = createHardwareProperties(deviceContext); + mGestureInterpreter->SetHardwareProperties(mHardwareProperties); // Even though we don't explicitly delete copy/move semantics, it's safe to // give away pointers to TouchpadInputMapper and its members here because // 1) mGestureInterpreter's lifecycle is determined by TouchpadInputMapper, and @@ -372,6 +374,7 @@ std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when, .setBoolValues({config.touchpadTapDraggingEnabled}); mPropertyProvider.getProperty("Button Right Click Zone Enable") .setBoolValues({config.touchpadRightClickZoneEnabled}); + mTouchpadHardwareStateNotificationsEnabled = config.shouldNotifyTouchpadHardwareState; } std::list<NotifyArgs> out; if ((!changes.any() && config.pointerCaptureRequest.isEnable()) || @@ -421,6 +424,9 @@ std::list<NotifyArgs> TouchpadInputMapper::process(const RawEvent& rawEvent) { } std::optional<SelfContainedHardwareState> state = mStateConverter.processRawEvent(rawEvent); if (state) { + if (mTouchpadHardwareStateNotificationsEnabled) { + getPolicy()->notifyTouchpadHardwareState(*state, rawEvent.deviceId); + } updatePalmDetectionMetrics(); return sendHardwareState(rawEvent.when, rawEvent.readTime, *state); } else { @@ -493,4 +499,8 @@ std::optional<ui::LogicalDisplayId> TouchpadInputMapper::getAssociatedDisplayId( return mDisplayId; } +std::optional<HardwareProperties> TouchpadInputMapper::getTouchpadHardwareProperties() { + return mHardwareProperties; +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h index 8baa63e8e0..a2c4be9e50 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h @@ -68,6 +68,8 @@ public: std::optional<ui::LogicalDisplayId> getAssociatedDisplayId() override; + std::optional<HardwareProperties> getTouchpadHardwareProperties() override; + private: void resetGestureInterpreter(nsecs_t when); explicit TouchpadInputMapper(InputDeviceContext& deviceContext, @@ -92,6 +94,7 @@ private: HardwareStateConverter mStateConverter; GestureConverter mGestureConverter; CapturedTouchpadEventConverter mCapturedEventConverter; + HardwareProperties mHardwareProperties; bool mPointerCaptured = false; bool mResettingInterpreter = false; @@ -112,6 +115,10 @@ private: std::optional<ui::LogicalDisplayId> mDisplayId; nsecs_t mGestureStartTime{0}; + + // True if hardware state update notifications is available for usage based on its feature flag + // and settings value. + bool mTouchpadHardwareStateNotificationsEnabled = false; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h index 66d62f856b..148ca5aa9e 100644 --- a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h +++ b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.h @@ -28,6 +28,7 @@ #include "accumulator/TouchButtonAccumulator.h" #include "include/TouchpadHardwareState.h" +#include "TouchpadHardwareState.h" #include "include/gestures.h" namespace android { diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp index b738abf6d2..d39ad3fd1e 100644 --- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp +++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp @@ -20,6 +20,7 @@ #include <memory> #include <EventHub.h> +#include <com_android_input_flags.h> #include <gtest/gtest.h> #include <linux/input-event-codes.h> #include <linux/input.h> @@ -32,9 +33,14 @@ #include "TestEventMatchers.h" #include "TestInputListener.h" +namespace input_flags = com::android::input::flags; + namespace android { using testing::AllOf; +using testing::Each; +using testing::ElementsAre; +using testing::VariantWith; class CapturedTouchpadEventConverterTest : public testing::Test { public: @@ -44,6 +50,8 @@ public: mReader(mFakeEventHub, mFakePolicy, mFakeListener), mDevice(newDevice()), mDeviceContext(*mDevice, EVENTHUB_ID) { + input_flags::include_relative_axis_values_for_captured_touchpads(true); + const size_t slotCount = 8; mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0); mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true); @@ -123,7 +131,7 @@ protected: TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populatedCorrectly) { mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, 0, 4000, 0, 0, 45); - mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, 0, 2500, 0, 0, 40); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 2000, 0, 0, 40); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1100, 0, 0, 35); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 30); mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 900, 0, 0, 25); @@ -147,8 +155,8 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated const InputDeviceInfo::MotionRange* posY = info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, posY); - EXPECT_NEAR(0, posY->min, EPSILON); - EXPECT_NEAR(2500, posY->max, EPSILON); + EXPECT_NEAR(-500, posY->min, EPSILON); + EXPECT_NEAR(2000, posY->max, EPSILON); EXPECT_NEAR(40, posY->resolution, EPSILON); const InputDeviceInfo::MotionRange* touchMajor = @@ -179,8 +187,22 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated EXPECT_NEAR(800, toolMinor->max, EPSILON); EXPECT_NEAR(20, toolMinor->resolution, EPSILON); - // ...except orientation and pressure, which get scaled, and size, which is generated from other - // values. + // ...except for the relative motion axes, derived from the corresponding absolute ones: + const InputDeviceInfo::MotionRange* relX = + info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD); + ASSERT_NE(nullptr, relX); + EXPECT_NEAR(-4000, relX->min, EPSILON); + EXPECT_NEAR(4000, relX->max, EPSILON); + EXPECT_NEAR(45, relX->resolution, EPSILON); + + const InputDeviceInfo::MotionRange* relY = + info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD); + ASSERT_NE(nullptr, relY); + EXPECT_NEAR(-2500, relY->min, EPSILON); + EXPECT_NEAR(2500, relY->max, EPSILON); + EXPECT_NEAR(40, relY->resolution, EPSILON); + + // ...orientation and pressure, which get scaled: const InputDeviceInfo::MotionRange* orientation = info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, orientation); @@ -195,6 +217,7 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated EXPECT_NEAR(1, pressure->max, EPSILON); EXPECT_NEAR(0, pressure->resolution, EPSILON); + // ... and size, which is generated from other values. const InputDeviceInfo::MotionRange* size = info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD); ASSERT_NE(nullptr, size); @@ -216,7 +239,9 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_bareMinimumAxesPresent_p // present, since it's generated from axes that aren't provided by this device). EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD)); EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD)); - EXPECT_EQ(2u, info.getMotionRanges().size()); + EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD)); + EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD)); + EXPECT_EQ(4u, info.getMotionRanges().size()); } TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { @@ -232,28 +257,31 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(50, 100), WithToolType(ToolType::FINGER))); + WithCoords(50, 100), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 99); EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 99), WithToolType(ToolType::FINGER))); + WithCoords(52, 99), WithRelativeMotion(2, -1), + WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); processAxis(conv, EV_KEY, BTN_TOUCH, 0); processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 99), WithToolType(ToolType::FINGER))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithPointerCount(1u), - WithCoords(52, 99), WithToolType(ToolType::FINGER))); + EXPECT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_UP)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithCoords(52, 99), WithRelativeMotion(0, 0), WithPointerCount(1u), + WithToolType(ToolType::FINGER))))); } TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) { @@ -504,13 +532,13 @@ TEST_F(CapturedTouchpadEventConverterTest, PalmTurningIntoFinger_reported) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(51, 100))); + WithCoords(51, 100), WithRelativeMotion(0, 0))); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 100))); + WithCoords(52, 100), WithRelativeMotion(1, 0))); } TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) { @@ -550,7 +578,7 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerRep EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(98, 148))); + WithCoords(98, 148), WithRelativeMotion(-2, -2))); } TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) { @@ -572,17 +600,17 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partia processAxis(conv, EV_KEY, BTN_TOUCH, 1); processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithToolType(ToolType::FINGER))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerCount(2u), WithPointerToolType(0, ToolType::FINGER), - WithPointerToolType(1, ToolType::FINGER))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithPointerCount(1u), WithToolType(ToolType::FINGER))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerCount(2u), + WithPointerToolType(0, ToolType::FINGER), + WithPointerToolType(1, ToolType::FINGER))))); processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51); @@ -591,15 +619,16 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partia processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251); processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM); - args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithFlags(AMOTION_EVENT_FLAG_CANCELED), WithPointerCount(2u))); + std::list<NotifyArgs> args = processSync(conv); + EXPECT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithFlags(AMOTION_EVENT_FLAG_CANCELED))))); + EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithPointerCount(2u)))); } TEST_F(CapturedTouchpadEventConverterTest, FingerAndPalmTurningIntoFinger_reported) { @@ -632,15 +661,15 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerAndPalmTurningIntoFinger_report processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251); processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerCount(2u))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithPointerCount(1u))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerCount(2u))))); } TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { @@ -656,7 +685,8 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithCoords(50, 100), WithToolType(ToolType::FINGER))); + WithCoords(50, 100), WithRelativeMotion(0, 0), + WithToolType(ToolType::FINGER))); processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52); @@ -670,18 +700,22 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(52, 99), WithToolType(ToolType::FINGER))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerCount(2u), WithPointerCoords(0, 52, 99), - WithPointerCoords(1, 250, 200), WithPointerToolType(0, ToolType::FINGER), - WithPointerToolType(1, ToolType::FINGER))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithPointerCount(1u), WithCoords(52, 99), + WithRelativeMotion(2, -1), + WithToolType(ToolType::FINGER))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerCount(2u), WithPointerCoords(0, 52, 99), + WithPointerRelativeMotion(0, 0, 0), + WithPointerCoords(1, 250, 200), + WithPointerRelativeMotion(1, 0, 0), + WithPointerToolType(0, ToolType::FINGER), + WithPointerToolType(1, ToolType::FINGER))))); processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); @@ -692,34 +726,96 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) { processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 0); - args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u), - WithPointerCoords(0, 52, 99), WithPointerCoords(1, 255, 202), - WithPointerToolType(1, ToolType::FINGER), - WithPointerToolType(0, ToolType::FINGER))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerCount(2u), WithPointerCoords(0, 52, 99), - WithPointerCoords(1, 255, 202), WithPointerToolType(0, ToolType::FINGER), - WithPointerToolType(1, ToolType::FINGER))); + std::list<NotifyArgs> args = processSync(conv); + EXPECT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithPointerRelativeMotion(1, 5, 2))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerRelativeMotion(1, 0, 0))))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>( + AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99), + WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 255, 202), + WithPointerToolType(1, ToolType::FINGER), + WithPointerToolType(0, ToolType::FINGER))))); processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); processAxis(conv, EV_KEY, BTN_TOUCH, 0); args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), + EXPECT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_UP)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202), + WithPointerRelativeMotion(1, 0, 0), + WithToolType(ToolType::FINGER))))); +} + +TEST_F(CapturedTouchpadEventConverterTest, RelativeMotionAxesClearedForNewFingerInSlot) { + CapturedTouchpadEventConverter conv = createConverter(); + // Put down one finger. + processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); + processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1); + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100); + + processAxis(conv, EV_KEY, BTN_TOUCH, 1); + processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), + WithCoords(50, 100), WithRelativeMotion(0, 0))); + + // Move it in negative X and Y directions. + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 47); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 97); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(47, 97), + WithRelativeMotion(-3, -3))); + + // Lift it. + processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); + processAxis(conv, EV_KEY, BTN_TOUCH, 0); + processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); + + std::list<NotifyArgs> args = processSync(conv); + EXPECT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_UP)))); + EXPECT_THAT(args, + Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(47, 97), + WithRelativeMotion(0, 0), + WithPointerCount(1u))))); + + // Put down another finger using the same slot. Relative axis values should be cleared. + processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2); + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 60); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 60); + + processAxis(conv, EV_KEY, BTN_TOUCH, 1); + processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), + WithCoords(60, 60), WithRelativeMotion(0, 0))); + + processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 64); + processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 58); + + EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), - WithCoords(255, 202), WithToolType(ToolType::FINGER))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithPointerCount(1u), - WithCoords(255, 202), WithToolType(ToolType::FINGER))); + WithCoords(64, 58), WithRelativeMotion(4, -2))); } // Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out. @@ -737,17 +833,18 @@ TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) { processAxis(conv, EV_KEY, BTN_TOUCH, 1); processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u), - WithPointerId(/*index=*/0, /*id=*/0))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/0), - WithPointerId(/*index=*/1, /*id=*/1))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithPointerCount(1u), + WithPointerId(/*index=*/0, /*id=*/0))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerCount(2u), + WithPointerId(/*index=*/0, /*id=*/0), + WithPointerId(/*index=*/1, /*id=*/1))))); // Lift the finger in slot 0, freeing up pointer ID 0... processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); @@ -758,27 +855,30 @@ TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) { processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 3); processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 30); - args = processSync(conv); - ASSERT_EQ(3u, args.size()); + std::list<NotifyArgs> args = processSync(conv); // Slot 1 being present will result in a MOVE event, even though it hasn't actually moved (see // comments in CapturedTouchpadEventConverter::sync). - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u), - WithPointerId(/*index=*/0, /*id=*/0), WithPointerId(/*index=*/1, /*id=*/1))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | - 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/0), - WithPointerId(/*index=*/1, /*id=*/1))); - args.pop_front(); - // Slot 0 being lifted causes the finger from slot 1 to move up to index 0, but keep its - // previous ID. The new finger in slot 2 should take ID 0, which was just freed up. - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | - 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/1), - WithPointerId(/*index=*/1, /*id=*/0))); + EXPECT_THAT(args, + ElementsAre(VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithPointerId(/*index=*/0, /*id=*/0), + WithPointerId(/*index=*/1, /*id=*/1))), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_UP | + 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerId(/*index=*/0, /*id=*/0), + WithPointerId(/*index=*/1, /*id=*/1))), + // Slot 0 being lifted causes the finger from slot 1 to move up to index + // 0, but keep its previous ID. The new finger in slot 2 should take ID + // 0, which was just freed up. + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_POINTER_DOWN | + 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + WithPointerId(/*index=*/0, /*id=*/1), + WithPointerId(/*index=*/1, /*id=*/0))))); + EXPECT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithPointerCount(2u)))); } // Motion events without any pointers are invalid, so when a button press is reported in the same @@ -797,33 +897,30 @@ TEST_F(CapturedTouchpadEventConverterTest, processAxis(conv, EV_KEY, BTN_LEFT, 1); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u), - WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithPointerCount(1u), WithCoords(50, 100), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))))); processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); processAxis(conv, EV_KEY, BTN_TOUCH, 0); processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); processAxis(conv, EV_KEY, BTN_LEFT, 0); - args = processSync(conv); - ASSERT_EQ(3u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u), - WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(0))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_UP)); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithPointerCount(1u), WithCoords(50, 100), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(0))), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_UP)))); } // Some touchpads sometimes report a button press before they report the finger touching the pad. In @@ -841,15 +938,14 @@ TEST_F(CapturedTouchpadEventConverterTest, ButtonPressedBeforeTouch_ReportedOnce processAxis(conv, EV_KEY, BTN_TOUCH, 1); processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u), - WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithPointerCount(1u), WithCoords(50, 100), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))))); } // When all fingers are lifted from a touchpad, we should release any buttons that are down, since @@ -866,29 +962,25 @@ TEST_F(CapturedTouchpadEventConverterTest, ButtonReleasedAfterTouchLifts_Reporte processAxis(conv, EV_KEY, BTN_LEFT, 1); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN)), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)))); processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); processAxis(conv, EV_KEY, BTN_TOUCH, 0); processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); - args = processSync(conv); - ASSERT_EQ(3u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u), - WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(0))); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_UP)); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithPointerCount(1u), WithCoords(50, 100), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(0))), + VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_UP)))); processAxis(conv, EV_KEY, BTN_LEFT, 0); ASSERT_EQ(0u, processSync(conv).size()); @@ -908,48 +1000,41 @@ TEST_F(CapturedTouchpadEventConverterTest, MultipleButtonsPressedDuringTouch_Rep WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); processAxis(conv, EV_KEY, BTN_LEFT, 1); - std::list<NotifyArgs> args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))))); processAxis(conv, EV_KEY, BTN_RIGHT, 1); - args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | - AMOTION_EVENT_BUTTON_SECONDARY))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | + AMOTION_EVENT_BUTTON_SECONDARY))))); processAxis(conv, EV_KEY, BTN_LEFT, 0); - args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), - WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), + WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY))))); processAxis(conv, EV_KEY, BTN_RIGHT, 0); - args = processSync(conv); - ASSERT_EQ(2u, args.size()); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); - args.pop_front(); - EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0))); + EXPECT_THAT(processSync(conv), + ElementsAre(VariantWith<NotifyMotionArgs>( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE)), + VariantWith<NotifyMotionArgs>( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), + WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), + WithButtonState(0))))); } } // namespace android diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index 6099c91daf..d77d539f74 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -65,6 +65,17 @@ void FakeInputReaderPolicy::assertStylusGestureNotNotified() { ASSERT_FALSE(mDeviceIdOfNotifiedStylusGesture); } +void FakeInputReaderPolicy::assertTouchpadHardwareStateNotified() { + std::unique_lock lock(mLock); + base::ScopedLockAssertion assumeLocked(mLock); + + const bool success = + mTouchpadHardwareStateNotified.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) { + return mTouchpadHardwareState.has_value(); + }); + ASSERT_TRUE(success) << "Timed out waiting for hardware state to be notified"; +} + void FakeInputReaderPolicy::clearViewports() { mViewports.clear(); mConfig.setDisplayViewports(mViewports); @@ -234,6 +245,13 @@ void FakeInputReaderPolicy::notifyInputDevicesChanged( mDevicesChangedCondition.notify_all(); } +void FakeInputReaderPolicy::notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, + int32_t deviceId) { + std::scoped_lock lock(mLock); + mTouchpadHardwareState = schs; + mTouchpadHardwareStateNotified.notify_all(); +} + std::shared_ptr<KeyCharacterMap> FakeInputReaderPolicy::getKeyboardLayoutOverlay( const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) { return nullptr; diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index 94f1311a1e..e5ba620555 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -42,6 +42,7 @@ public: void assertInputDevicesNotChanged(); void assertStylusGestureNotified(int32_t deviceId); void assertStylusGestureNotNotified(); + void assertTouchpadHardwareStateNotified(); virtual void clearViewports(); std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueId) const; @@ -82,6 +83,8 @@ public: private: void getReaderConfiguration(InputReaderConfiguration* outConfig) override; void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override; + void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, + int32_t deviceId) override; std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier&, const std::optional<KeyboardLayoutInfo>) override; std::string getDeviceAlias(const InputDeviceIdentifier&) override; @@ -101,6 +104,9 @@ private: std::condition_variable mStylusGestureNotifiedCondition; std::optional<DeviceId> mDeviceIdOfNotifiedStylusGesture GUARDED_BY(mLock){}; + std::condition_variable mTouchpadHardwareStateNotified; + std::optional<SelfContainedHardwareState> mTouchpadHardwareState GUARDED_BY(mLock){}; + uint32_t mNextPointerCaptureSequenceNumber{0}; }; diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h index cfedc6eb1a..f3be04115a 100644 --- a/services/inputflinger/tests/TestEventMatchers.h +++ b/services/inputflinger/tests/TestEventMatchers.h @@ -654,6 +654,15 @@ MATCHER_P2(WithRelativeMotion, x, y, "InputEvent with specified relative motion" return argX == x && argY == y; } +MATCHER_P3(WithPointerRelativeMotion, pointer, x, y, + "InputEvent with specified relative motion for pointer") { + const auto argX = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); + const auto argY = arg.pointerCoords[pointer].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); + *result_listener << "expected pointer " << pointer << " to have relative motion (" << x << ", " + << y << "), but got (" << argX << ", " << argY << ")"; + return argX == x && argY == y; +} + MATCHER_P3(WithGestureOffset, dx, dy, epsilon, "InputEvent with specified touchpad gesture offset") { const auto argGestureX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET); diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp index fc8a7dafb0..ea69fffeaa 100644 --- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp +++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp @@ -172,4 +172,22 @@ TEST_F(TouchpadInputMapperTest, HoverAndLeftButtonPress) { ASSERT_THAT(args, testing::IsEmpty()); } +TEST_F(TouchpadInputMapperTest, TouchpadHardwareState) { + mReaderConfiguration.shouldNotifyTouchpadHardwareState = true; + std::list<NotifyArgs> args = + mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, + InputReaderConfiguration::Change::TOUCHPAD_SETTINGS); + + args += process(EV_ABS, ABS_MT_TRACKING_ID, 1); + args += process(EV_KEY, BTN_TOUCH, 1); + setScanCodeState(KeyState::DOWN, {BTN_TOOL_FINGER}); + args += process(EV_KEY, BTN_TOOL_FINGER, 1); + args += process(EV_ABS, ABS_MT_POSITION_X, 50); + args += process(EV_ABS, ABS_MT_POSITION_Y, 50); + args += process(EV_ABS, ABS_MT_PRESSURE, 1); + args += process(EV_SYN, SYN_REPORT, 0); + + mFakePolicy->assertTouchpadHardwareStateNotified(); +} + } // namespace android diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp index d552c19532..3e4a19becd 100644 --- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp @@ -117,6 +117,10 @@ public: return reader->getSensors(deviceId); } + std::optional<HardwareProperties> getTouchpadHardwareProperties(int32_t deviceId) { + return reader->getTouchpadHardwareProperties(deviceId); + } + bool canDispatchToDisplay(int32_t deviceId, ui::LogicalDisplayId displayId) { return reader->canDispatchToDisplay(deviceId, displayId); } diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index fea0d9a1c1..ddc3310448 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -281,6 +281,8 @@ public: FuzzInputReaderPolicy(std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp) : mFdp(mFdp) {} void getReaderConfiguration(InputReaderConfiguration* outConfig) override {} void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {} + void notifyTouchpadHardwareState(const SelfContainedHardwareState& schs, + int32_t deviceId) override {} std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay( const InputDeviceIdentifier& identifier, const std::optional<KeyboardLayoutInfo> layoutInfo) override { diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 6b4215e2f4..abeb2a92eb 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -21,7 +21,7 @@ #include <private/android_filesystem_config.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/SchedulingPolicy.h> #include "Client.h" diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index d50a0bcec1..0eced73ff9 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -44,6 +44,7 @@ using hardware::Return; using aidl::android::hardware::graphics::composer3::BnComposerCallback; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; +using aidl::android::hardware::graphics::composer3::Lut; using aidl::android::hardware::graphics::composer3::PowerMode; using aidl::android::hardware::graphics::composer3::VirtualDisplay; @@ -1539,6 +1540,18 @@ Error AidlComposer::getClientTargetProperty( return error; } +Error AidlComposer::getDisplayLuts(Display display, std::vector<Lut>* outLuts) { + Error error = Error::NONE; + mMutex.lock_shared(); + if (auto reader = getReader(display)) { + *outLuts = reader->get().takeDisplayLuts(translate<int64_t>(display)); + } else { + error = Error::BAD_DISPLAY; + } + mMutex.unlock_shared(); + return error; +} + Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) { Error error = Error::NONE; mMutex.lock_shared(); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index ea0e53a202..3669d4c996 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -244,6 +244,9 @@ public: Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override; Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, int32_t frameIntervalNs) override; + Error getDisplayLuts( + Display display, + std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) override; private: // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index bc067a0e5d..888dc08134 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -41,6 +41,7 @@ #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> #include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h> #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h> +#include <aidl/android/hardware/graphics/composer3/Lut.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <aidl/android/hardware/graphics/common/Transform.h> @@ -303,6 +304,7 @@ public: virtual Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) = 0; virtual Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, int32_t frameIntervalNs) = 0; + virtual Error getDisplayLuts(Display display, std::vector<V3_0::Lut>* outLuts) = 0; }; } // namespace Hwc2 diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index c77cdd4432..748765a4e4 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -31,10 +31,11 @@ #include <utils/String8.h> #include <log/log.h> -#include <hardware/hardware.h> +#include <com_android_graphics_libgui_flags.h> #include <gui/BufferItem.h> #include <gui/BufferQueue.h> #include <gui/Surface.h> +#include <hardware/hardware.h> #include <ui/DebugUtils.h> #include <ui/GraphicBuffer.h> @@ -48,10 +49,18 @@ namespace android { using ui::Dataspace; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, + const sp<IGraphicBufferProducer>& producer, + const sp<IGraphicBufferConsumer>& consumer, + const ui::Size& size, const ui::Size& maxSize) + : ConsumerBase(producer, consumer), +#else FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp<IGraphicBufferConsumer>& consumer, const ui::Size& size, const ui::Size& maxSize) : ConsumerBase(consumer), +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) mDisplayId(displayId), mMaxSize(maxSize), mCurrentBufferSlot(-1), diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 2728cf637e..6ca64a2437 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -20,6 +20,7 @@ #include <stdint.h> #include <sys/types.h> +#include <com_android_graphics_libgui_flags.h> #include <compositionengine/DisplaySurface.h> #include <gui/BufferQueue.h> #include <gui/ConsumerBase.h> @@ -40,9 +41,16 @@ class HWComposer; class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface { public: +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, + const sp<IGraphicBufferProducer>& producer, const sp<IGraphicBufferConsumer>& consumer, const ui::Size& size, const ui::Size& maxSize); +#else + FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, + const sp<IGraphicBufferConsumer>& consumer, const ui::Size& size, + const ui::Size& maxSize); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 8c0f81e051..d5f65c6211 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -41,6 +41,7 @@ using aidl::android::hardware::graphics::composer3::Color; using aidl::android::hardware::graphics::composer3::Composition; using AidlCapability = aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; +using aidl::android::hardware::graphics::composer3::Lut; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -607,6 +608,18 @@ Error Display::getClientTargetProperty( return static_cast<Error>(error); } +Error Display::getDisplayLuts(std::vector<Lut>* outLuts) { + std::vector<Lut> tmpLuts; + const auto error = mComposer.getDisplayLuts(mId, &tmpLuts); + for (Lut& lut : tmpLuts) { + if (lut.pfd.get() >= 0) { + outLuts->push_back( + {lut.layer, ndk::ScopedFileDescriptor(lut.pfd.release()), lut.lutProperties}); + } + } + return static_cast<Error>(error); +} + Error Display::getDisplayDecorationSupport( std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* support) { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 5b948318ae..be2059a935 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -45,6 +45,7 @@ #include <aidl/android/hardware/graphics/composer3/Color.h> #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> +#include <aidl/android/hardware/graphics/composer3/Lut.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h> @@ -178,6 +179,8 @@ public: [[nodiscard]] virtual hal::Error getClientTargetProperty( aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness* outClientTargetProperty) = 0; + [[nodiscard]] virtual hal::Error getDisplayLuts( + std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) = 0; [[nodiscard]] virtual hal::Error getDisplayDecorationSupport( std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* support) = 0; @@ -261,6 +264,8 @@ public: hal::Error getClientTargetProperty( aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness* outClientTargetProperty) override; + hal::Error getDisplayLuts( + std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) override; hal::Error getDisplayDecorationSupport( std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* support) override; diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 7c4aa7530d..ec2a3ec024 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -46,6 +46,7 @@ using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; using aidl::android::hardware::graphics::composer3::DimmingStage; using aidl::android::hardware::graphics::composer3::DisplayCapability; +using aidl::android::hardware::graphics::composer3::Lut; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -1408,6 +1409,10 @@ Error HidlComposer::getClientTargetProperty( return Error::NONE; } +Error HidlComposer::getDisplayLuts(Display, std::vector<Lut>*) { + return Error::NONE; +} + Error HidlComposer::setLayerBrightness(Display, Layer, float) { return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index d78bfb7c6b..8bca5ad31f 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -351,6 +351,8 @@ public: Hdr*) override; Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override; Error notifyExpectedPresent(Display, nsecs_t, int32_t) override; + Error getDisplayLuts(Display, + std::vector<aidl::android::hardware::graphics::composer3::Lut>*) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 4b5a68cefa..384f7b22c7 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -22,6 +22,7 @@ #include <cinttypes> +#include <com_android_graphics_libgui_flags.h> #include <ftl/enum.h> #include <ftl/flags.h> #include <gui/BufferItem.h> @@ -51,7 +52,11 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d const sp<IGraphicBufferProducer>& bqProducer, const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name) +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + : ConsumerBase(bqProducer, bqConsumer), +#else : ConsumerBase(bqConsumer), +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) mHwc(hwc), mDisplayId(displayId), mDisplayName(name), diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 2a0ee5a993..3736abc79f 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -697,6 +697,23 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, jd.jankType = mJankType; jd.frameIntervalNs = (mRenderRate ? *mRenderRate : mDisplayFrameRenderRate).getPeriodNsecs(); + + if (mPredictionState == PredictionState::Valid) { + jd.scheduledAppFrameTimeNs = mPredictions.endTime - mPredictions.startTime; + + // Using expected start, rather than actual, to measure the entire frame time. That is + // if the application starts the frame later than scheduled, include that delay in the + // frame time, as it usually means main thread being busy with non-rendering work. + if (mPresentState == PresentState::Dropped) { + jd.actualAppFrameTimeNs = mDropTime - mPredictions.startTime; + } else { + jd.actualAppFrameTimeNs = mActuals.endTime - mPredictions.startTime; + } + } else { + jd.scheduledAppFrameTimeNs = 0; + jd.actualAppFrameTimeNs = 0; + } + JankTracker::onJankData(mLayerId, jd); } } diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp index f4335f36bc..d709530990 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp @@ -18,6 +18,8 @@ #undef LOG_TAG #define LOG_TAG "SurfaceFlinger" +#include <android-base/logging.h> + #include "LayerHierarchy.h" #include "LayerLog.h" #include "SwapErase.h" @@ -485,6 +487,55 @@ LayerHierarchy* LayerHierarchyBuilder::getHierarchyFromId(uint32_t layerId, bool return it->second; } +void LayerHierarchyBuilder::logSampledChildren(const LayerHierarchy& hierarchy) const { + LOG(ERROR) << "Dumping random sampling of child layers."; + int sampleSize = static_cast<int>(hierarchy.mChildren.size() / 100 + 1); + for (const auto& [child, variant] : hierarchy.mChildren) { + if (rand() % sampleSize == 0) { + LOG(ERROR) << "Child Layer: " << *(child->mLayer); + } + } +} + +void LayerHierarchyBuilder::dumpLayerSample(const LayerHierarchy& root) const { + LOG(ERROR) << "Dumping layer keeping > 20 children alive:"; + // If mLayer is nullptr, it will be skipped while traversing. + if (!root.mLayer && root.mChildren.size() > 20) { + LOG(ERROR) << "ROOT has " << root.mChildren.size() << " children"; + logSampledChildren(root); + } + root.traverse([&](const LayerHierarchy& hierarchy, const auto&) -> bool { + if (hierarchy.mChildren.size() <= 20) { + return true; + } + // mLayer is ensured to be non-null. See LayerHierarchy::traverse. + const auto* layer = hierarchy.mLayer; + const auto childrenCount = hierarchy.mChildren.size(); + LOG(ERROR) << "Layer " << *layer << " has " << childrenCount << " children"; + + const auto* parent = hierarchy.mParent; + while (parent != nullptr) { + if (!parent->mLayer) break; + LOG(ERROR) << "Parent Layer: " << *(parent->mLayer); + parent = parent->mParent; + } + + logSampledChildren(hierarchy); + // Stop traversing. + return false; + }); + LOG(ERROR) << "Dumping random sampled layers."; + size_t numLayers = 0; + root.traverse([&](const LayerHierarchy& hierarchy, const auto&) -> bool { + if (hierarchy.mLayer) numLayers++; + if ((rand() % 20 == 13) && hierarchy.mLayer) { + LOG(ERROR) << "Layer: " << *(hierarchy.mLayer); + } + return true; + }); + LOG(ERROR) << "Total layer count: " << numLayers; +} + const LayerHierarchy::TraversalPath LayerHierarchy::TraversalPath::ROOT = {.id = UNASSIGNED_LAYER_ID, .variant = LayerHierarchy::Attached}; diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h index d023f9e9f5..47d0041a8b 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -211,8 +211,11 @@ public: const LayerHierarchy& getHierarchy() const; const LayerHierarchy& getOffscreenHierarchy() const; std::string getDebugString(uint32_t layerId, uint32_t depth = 0) const; + void dumpLayerSample(const LayerHierarchy& layerHierarchy) const; private: + void logSampledChildren(const LayerHierarchy& hierarchy) const; + void onLayerAdded(RequestedLayerState* layer); void attachToParent(LayerHierarchy*); void detachFromParent(LayerHierarchy*); diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index c874db358e..ac15b92175 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -1265,6 +1265,12 @@ void LayerSnapshotBuilder::forEachSnapshot(const Visitor& visitor, } } +void LayerSnapshotBuilder::forEachSnapshot(const ConstVisitor& visitor) const { + for (auto& snapshot : mSnapshots) { + visitor(*snapshot); + } +} + void LayerSnapshotBuilder::forEachInputSnapshot(const ConstVisitor& visitor) const { for (int i = mNumInterestingSnapshots - 1; i >= 0; i--) { LayerSnapshot& snapshot = *mSnapshots[(size_t)i]; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index 207e23a4c1..486cb33959 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -91,6 +91,9 @@ public: // snapshots in z-order void forEachSnapshot(const Visitor& visitor, const ConstPredicate& predicate); + // Visit each snapshot + void forEachSnapshot(const ConstVisitor& visitor) const; + // Visit each snapshot interesting to input reverse z-order void forEachInputSnapshot(const ConstVisitor& visitor) const; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index abdf92cd40..5d6e5ba232 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -317,7 +317,6 @@ void Layer::addToCurrentState() { if (mRemovedFromDrawingState) { mRemovedFromDrawingState = false; mFlinger->mScheduler->registerLayer(this, FrameRateCompatibility::Default); - mFlinger->removeFromOffscreenLayers(this); } for (const auto& child : mCurrentChildren) { @@ -1350,14 +1349,6 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const { return usage; } -void Layer::updateTransformHint(ui::Transform::RotationFlags transformHint) { - if (mFlinger->mDebugDisableTransformHint || transformHint & ui::Transform::ROT_INVALID) { - transformHint = ui::Transform::ROT_0; - } - - setTransformHintLegacy(transformHint); -} - // ---------------------------------------------------------------------------- // debugging // ---------------------------------------------------------------------------- @@ -2538,15 +2529,24 @@ void Layer::cloneDrawingState(const Layer* from) { void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, const sp<Fence>& releaseFence) { - if (!listener) { + if (!listener && !mBufferReleaseChannel) { return; } + SFTRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); + + ReleaseCallbackId callbackId{buffer->getId(), framenumber}; + const sp<Fence>& fence = releaseFence ? releaseFence : Fence::NO_FENCE; uint32_t currentMaxAcquiredBufferCount = mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); - listener->onReleaseBuffer({buffer->getId(), framenumber}, - releaseFence ? releaseFence : Fence::NO_FENCE, - currentMaxAcquiredBufferCount); + + if (listener) { + listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount); + } + + if (mBufferReleaseChannel) { + mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount); + } } sp<CallbackHandle> Layer::findCallbackHandle() { @@ -2664,6 +2664,7 @@ void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { + handle->bufferReleaseChannel = mBufferReleaseChannel; handle->transformHint = mTransformHint; handle->dequeueReadyTime = dequeueReadyTime; handle->currentMaxAcquiredBufferCount = @@ -4001,13 +4002,6 @@ sp<GraphicBuffer> Layer::getBuffer() const { return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; } -void Layer::setTransformHintLegacy(ui::Transform::RotationFlags displayTransformHint) { - mTransformHintLegacy = getFixedTransformHint(); - if (mTransformHintLegacy == ui::Transform::ROT_INVALID) { - mTransformHintLegacy = displayTransformHint; - } -} - const std::shared_ptr<renderengine::ExternalTexture>& Layer::getExternalTexture() const { return mBufferInfo.mBuffer; } @@ -4109,6 +4103,11 @@ bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thre return haveTrustedPresentationListener; } +void Layer::setBufferReleaseChannel( + const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel) { + mBufferReleaseChannel = channel; +} + void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 948c62df3c..32dbe34408 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -543,6 +543,7 @@ public: }; BufferInfo mBufferInfo; + std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel; // implements compositionengine::LayerFE const compositionengine::LayerFECompositionState* getCompositionState() const; @@ -687,10 +688,6 @@ public: */ void addToCurrentState(); - /* - * Sets display transform hint on BufferLayerConsumer. - */ - void updateTransformHint(ui::Transform::RotationFlags); inline const State& getDrawingState() const { return mDrawingState; } inline State& getDrawingState() { return mDrawingState; } @@ -802,6 +799,8 @@ public: bool setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, TrustedPresentationListener const& listener); + void setBufferReleaseChannel( + const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel); // Creates a new handle each time, so we only expect // this to be called once. @@ -1212,13 +1211,11 @@ private: bool findInHierarchy(const sp<Layer>&); - void setTransformHintLegacy(ui::Transform::RotationFlags); void releasePreviousBuffer(); void resetDrawingStateBufferInfo(); // Transform hint provided to the producer. This must be accessed holding // the mStateLock. - ui::Transform::RotationFlags mTransformHintLegacy = ui::Transform::ROT_0; std::optional<ui::Transform::RotationFlags> mTransformHint = std::nullopt; ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index a1a60e3e30..dbc458cb7f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -595,6 +595,12 @@ bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { return true; } + if (FlagManager::getInstance().view_set_requested_frame_rate_mrr() && + category == FrameRateCategory::NoPreference && vote.rate.isValid() && + vote.type == FrameRateCompatibility::ExactOrMultiple) { + return true; + } + return false; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 727541ef99..be00079b9c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -122,6 +122,12 @@ void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) { demotePacesetterDisplay(kPromotionParams); promotePacesetterDisplay(pacesetterId, kPromotionParams); + + // Cancel the pending refresh rate change, if any, before updating the phase configuration. + mVsyncModulator->cancelRefreshRateChange(); + + mVsyncConfiguration->reset(); + updatePhaseConfiguration(pacesetterId, pacesetterSelectorPtr()->getActiveMode().fps); } void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr, @@ -481,21 +487,18 @@ void Scheduler::setDuration(Cycle cycle, std::chrono::nanoseconds workDuration, } } -void Scheduler::updatePhaseConfiguration(Fps refreshRate) { +void Scheduler::updatePhaseConfiguration(PhysicalDisplayId displayId, Fps refreshRate) { + const bool isPacesetter = + FTL_FAKE_GUARD(kMainThreadContext, + (std::scoped_lock(mDisplayLock), displayId == mPacesetterDisplayId)); + if (!isPacesetter) return; + mRefreshRateStats->setRefreshRate(refreshRate); mVsyncConfiguration->setRefreshRateFps(refreshRate); setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()), refreshRate.getPeriod()); } -void Scheduler::resetPhaseConfiguration(Fps refreshRate) { - // Cancel the pending refresh rate change, if any, before updating the phase configuration. - mVsyncModulator->cancelRefreshRateChange(); - - mVsyncConfiguration->reset(); - updatePhaseConfiguration(refreshRate); -} - void Scheduler::setActiveDisplayPowerModeForRefreshRateStats(hal::PowerMode powerMode) { mRefreshRateStats->setPowerMode(powerMode); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 9b32fa99f2..1367ec385e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -187,8 +187,7 @@ public: } } - void updatePhaseConfiguration(Fps); - void resetPhaseConfiguration(Fps) REQUIRES(kMainThreadContext); + void updatePhaseConfiguration(PhysicalDisplayId, Fps); const VsyncConfiguration& getVsyncConfiguration() const { return *mVsyncConfiguration; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 79f11fb652..ab10ee4b69 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -40,6 +40,7 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> +#include <com_android_graphics_libgui_flags.h> #include <com_android_graphics_surfaceflinger_flags.h> #include <common/FlagManager.h> #include <common/trace.h> @@ -64,7 +65,7 @@ #include <ftl/fake_guard.h> #include <ftl/future.h> #include <ftl/unit.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> #include <gui/IProducerListener.h> @@ -1279,20 +1280,14 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken, return BAD_VALUE; } + // TODO: b/277364366 - Require a display token from clients and remove fallback to pacesetter. std::optional<PhysicalDisplayId> displayIdOpt; - { + if (displayToken) { Mutex::Autolock lock(mStateLock); - if (displayToken) { - displayIdOpt = getPhysicalDisplayIdLocked(displayToken); - if (!displayIdOpt) { - ALOGW("%s: Invalid physical display token %p", __func__, displayToken.get()); - return NAME_NOT_FOUND; - } - } else { - // TODO (b/277364366): Clients should be updated to pass in the display they - // want, rather than us picking an arbitrary one (the active display, in this - // case). - displayIdOpt = mActiveDisplayId; + displayIdOpt = getPhysicalDisplayIdLocked(displayToken); + if (!displayIdOpt) { + ALOGW("%s: Invalid physical display token %p", __func__, displayToken.get()); + return NAME_NOT_FOUND; } } @@ -1339,19 +1334,13 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { // VsyncController model is locked. mScheduler->modulateVsync(displayId, &VsyncModulator::onRefreshRateChangeInitiated); - if (displayId == mActiveDisplayId) { - mScheduler->updatePhaseConfiguration(mode.fps); - } - + mScheduler->updatePhaseConfiguration(displayId, mode.fps); mScheduler->setModeChangePending(true); break; } case DesiredModeAction::InitiateRenderRateSwitch: mScheduler->setRenderRate(displayId, mode.fps, /*applyImmediately*/ false); - - if (displayId == mActiveDisplayId) { - mScheduler->updatePhaseConfiguration(mode.fps); - } + mScheduler->updatePhaseConfiguration(displayId, mode.fps); if (emitEvent) { mScheduler->onDisplayModeChanged(displayId, mode); @@ -1446,9 +1435,7 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { mDisplayModeController.finalizeModeChange(displayId, activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(), activeMode.fps); - if (displayId == mActiveDisplayId) { - mScheduler->updatePhaseConfiguration(activeMode.fps); - } + mScheduler->updatePhaseConfiguration(displayId, activeMode.fps); if (pendingModeOpt->emitEvent) { mScheduler->onDisplayModeChanged(displayId, activeMode); @@ -1472,11 +1459,9 @@ void SurfaceFlinger::applyActiveMode(PhysicalDisplayId displayId) { constexpr bool kAllowToEnable = true; mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, std::move(activeModePtr).take()); - mScheduler->setRenderRate(displayId, renderFps, /*applyImmediately*/ true); - if (displayId == mActiveDisplayId) { - mScheduler->updatePhaseConfiguration(renderFps); - } + mScheduler->setRenderRate(displayId, renderFps, /*applyImmediately*/ true); + mScheduler->updatePhaseConfiguration(displayId, renderFps); } void SurfaceFlinger::initiateDisplayModeChanges() { @@ -2520,12 +2505,18 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, } updateLayerHistory(latchTime); - mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) { - if (mLayersIdsWithQueuedFrames.find(snapshot.path.id) == mLayersIdsWithQueuedFrames.end()) - return; - Region visibleReg; - visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion); - invalidateLayerStack(snapshot.outputFilter, visibleReg); + mLayerSnapshotBuilder.forEachSnapshot([&](const frontend::LayerSnapshot& snapshot) { + // update output dirty region if we have a queued buffer that is visible or a snapshot + // recently became invisible + // TODO(b/360050020) investigate if we need to update dirty region when layer color changes + if ((snapshot.isVisible && + (mLayersIdsWithQueuedFrames.find(snapshot.path.id) != + mLayersIdsWithQueuedFrames.end())) || + (!snapshot.isVisible && snapshot.changes.test(Changes::Visibility))) { + Region visibleReg; + visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion); + invalidateLayerStack(snapshot.outputFilter, visibleReg); + } }); for (auto& destroyedLayer : mLayerLifecycleManager.getDestroyedLayers()) { @@ -3722,11 +3713,20 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, state.surface.get()); const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId()); LOG_FATAL_IF(!displayId); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + const auto frameBufferSurface = + sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqProducer, bqConsumer, + state.physical->activeMode->getResolution(), + ui::Size(maxGraphicsWidth, maxGraphicsHeight)); + displaySurface = frameBufferSurface; + producer = frameBufferSurface->getSurface()->getIGraphicBufferProducer(); +#else displaySurface = sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer, state.physical->activeMode->getResolution(), ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) } LOG_FATAL_IF(!displaySurface); @@ -3830,11 +3830,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, setPowerModeInternal(display, hal::PowerMode::ON); } - // TODO(b/175678251) Call a listener instead. - if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) { - const Fps refreshRate = - mDisplayModeController.getActiveMode(display->getPhysicalId()).fps; - mScheduler->resetPhaseConfiguration(refreshRate); + if (display->getPhysicalId() == mActiveDisplayId) { + onActiveDisplayChangedLocked(nullptr, *display); } } return; @@ -3926,51 +3923,6 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { mUpdateInputInfo = true; } - // Update transform hint. - if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) { - // Layers and/or displays have changed, so update the transform hint for each layer. - // - // NOTE: we do this here, rather than when presenting the display so that - // the hint is set before we acquire a buffer from the surface texture. - // - // NOTE: layer transactions have taken place already, so we use their - // drawing state. However, SurfaceFlinger's own transaction has not - // happened yet, so we must use the current state layer list - // (soon to become the drawing state list). - // - sp<const DisplayDevice> hintDisplay; - ui::LayerStack layerStack; - - mCurrentState.traverse([&](Layer* layer) REQUIRES(mStateLock) { - // NOTE: we rely on the fact that layers are sorted by - // layerStack first (so we don't have to traverse the list - // of displays for every layer). - if (const auto filter = layer->getOutputFilter(); layerStack != filter.layerStack) { - layerStack = filter.layerStack; - hintDisplay = nullptr; - - // Find the display that includes the layer. - for (const auto& [token, display] : mDisplays) { - if (!display->getCompositionDisplay()->includesLayer(filter)) { - continue; - } - - // Pick the primary display if another display mirrors the layer. - if (hintDisplay) { - hintDisplay = nullptr; - break; - } - - hintDisplay = display; - } - } - - if (hintDisplay) { - layer->updateTransformHint(hintDisplay->getTransformHint()); - } - }); - } - if (mLayersAdded) { mLayersAdded = false; // Layers have been added. @@ -3984,14 +3936,6 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { mLayersRemoved = false; mVisibleRegionsDirty = true; mUpdateInputInfo = true; - mDrawingState.traverseInZOrder([&](Layer* layer) { - if (mLayersPendingRemoval.indexOf(sp<Layer>::fromExisting(layer)) >= 0) { - // this layer is not visible anymore - Region visibleReg; - visibleReg.set(layer->getScreenBounds()); - invalidateLayerStack(layer->getOutputFilter(), visibleReg); - } - }); } if (transactionFlags & eInputInfoUpdateNeeded) { @@ -4409,13 +4353,6 @@ void SurfaceFlinger::doCommitTransactions() { l->setIsAtRoot(false); mCurrentState.layersSortedByZ.remove(l); } - - // If the layer has been removed and has no parent, then it will not be reachable - // when traversing layers on screen. Add the layer to the offscreenLayers set to - // ensure we can copy its current to drawing state. - if (!l->getParent()) { - mOffscreenLayers.emplace(l.get()); - } } mLayersPendingRemoval.clear(); } @@ -4429,7 +4366,6 @@ void SurfaceFlinger::doCommitTransactions() { } } - commitOffscreenLayers(); if (mLayerMirrorRoots.size() > 0) { std::deque<Layer*> pendingUpdates; pendingUpdates.insert(pendingUpdates.end(), mLayerMirrorRoots.begin(), @@ -4451,17 +4387,6 @@ void SurfaceFlinger::doCommitTransactions() { } } -void SurfaceFlinger::commitOffscreenLayers() { - for (Layer* offscreenLayer : mOffscreenLayers) { - offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) { - if (layer->clearTransactionFlags(eTransactionNeeded)) { - layer->doTransaction(0); - layer->commitChildList(); - } - }); - } -} - void SurfaceFlinger::invalidateLayerStack(const ui::LayerFilter& layerFilter, const Region& dirty) { for (const auto& [token, displayDevice] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { auto display = displayDevice->getCompositionDisplay(); @@ -4475,65 +4400,26 @@ status_t SurfaceFlinger::addClientLayer(LayerCreationArgs& args, const sp<IBinde const sp<Layer>& layer, const wp<Layer>& parent, uint32_t* outTransformHint) { if (mNumLayers >= MAX_LAYERS) { + static std::atomic<nsecs_t> lasttime{0}; + nsecs_t now = systemTime(); + if (lasttime != 0 && ns2s(now - lasttime.load()) < 10) { + ALOGE("AddClientLayer already dumped 10s before"); + return NO_MEMORY; + } else { + lasttime = now; + } + ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), MAX_LAYERS); - static_cast<void>(mScheduler->schedule([=, this] { - ALOGE("Dumping layer keeping > 20 children alive:"); - bool leakingParentLayerFound = false; - mDrawingState.traverse([&](Layer* layer) { - if (leakingParentLayerFound) { - return; - } - if (layer->getChildrenCount() > 20) { - leakingParentLayerFound = true; - sp<Layer> parent = sp<Layer>::fromExisting(layer); - while (parent) { - ALOGE("Parent Layer: %s%s", parent->getName().c_str(), - (parent->isHandleAlive() ? "handleAlive" : "")); - parent = parent->getParent(); - } - // Sample up to 100 layers - ALOGE("Dumping random sampling of child layers total(%zu): ", - layer->getChildrenCount()); - int sampleSize = (layer->getChildrenCount() / 100) + 1; - layer->traverseChildren([&](Layer* layer) { - if (rand() % sampleSize == 0) { - ALOGE("Child Layer: %s%s", layer->getName().c_str(), - (layer->isHandleAlive() ? "handleAlive" : "")); - } - }); - } - }); - - int numLayers = 0; - mDrawingState.traverse([&](Layer* layer) { numLayers++; }); - - ALOGE("Dumping random sampling of on-screen layers total(%u):", numLayers); - mDrawingState.traverse([&](Layer* layer) { - // Aim to dump about 200 layers to avoid totally trashing - // logcat. On the other hand, if there really are 4096 layers - // something has gone totally wrong its probably the most - // useful information in logcat. - if (rand() % 20 == 13) { - ALOGE("Layer: %s%s", layer->getName().c_str(), - (layer->isHandleAlive() ? "handleAlive" : "")); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - }); - ALOGE("Dumping random sampling of off-screen layers total(%zu): ", - mOffscreenLayers.size()); - for (Layer* offscreenLayer : mOffscreenLayers) { - if (rand() % 20 == 13) { - ALOGE("Offscreen-layer: %s%s", offscreenLayer->getName().c_str(), - (offscreenLayer->isHandleAlive() ? "handleAlive" : "")); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - } + static_cast<void>(mScheduler->schedule([&]() FTL_FAKE_GUARD(kMainThreadContext) { + ALOGE("Dumping on-screen layers."); + mLayerHierarchyBuilder.dumpLayerSample(mLayerHierarchyBuilder.getHierarchy()); + ALOGE("Dumping off-screen layers."); + mLayerHierarchyBuilder.dumpLayerSample(mLayerHierarchyBuilder.getOffscreenHierarchy()); })); return NO_MEMORY; } - layer->updateTransformHint(mActiveDisplayTransformHint); if (outTransformHint) { *outTransformHint = mActiveDisplayTransformHint; } @@ -5229,6 +5115,10 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f } } + if (what & layer_state_t::eBufferReleaseChannelChanged) { + layer->setBufferReleaseChannel(s.bufferReleaseChannel); + } + const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence()); bool willPresentCurrentTransaction = requestedLayerState && (requestedLayerState->hasReadyFrame() || @@ -5748,7 +5638,7 @@ void SurfaceFlinger::logFrameStats(TimePoint now) { sTimestamp = now; SFTRACE_CALL(); - mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); }); + traverseLegacyLayers([&](Layer* layer) { layer->logFrameStats(); }); } void SurfaceFlinger::appendSfConfigString(std::string& result) const { @@ -6028,20 +5918,6 @@ perfetto::protos::LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t t .get(); } -void SurfaceFlinger::dumpOffscreenLayers(std::string& result) { - auto future = mScheduler->schedule([this] { - std::string result; - for (Layer* offscreenLayer : mOffscreenLayers) { - offscreenLayer->traverse(LayerVector::StateSet::Drawing, - [&](Layer* layer) { layer->dumpOffscreenDebugInfo(result); }); - } - return result; - }); - - result.append("Offscreen Layers:\n"); - result.append(future.get()); -} - void SurfaceFlinger::dumpHwcLayersMinidump(std::string& result) const { for (const auto& [token, display] : mDisplays) { const auto displayId = HalDisplayId::tryCast(display->getId()); @@ -6987,7 +6863,8 @@ static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if (uid == AID_GRAPHICS || PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + if (uid == AID_GRAPHICS || uid == AID_SYSTEM || + PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { return OK; } @@ -7082,7 +6959,8 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); - status_t validate = validateScreenshotPermissions(args); + const auto& captureArgs = args.captureArgs; + status_t validate = validateScreenshotPermissions(captureArgs); if (validate != OK) { ALOGD("Permission denied to captureDisplay"); invokeScreenCaptureError(validate, captureListener); @@ -7095,7 +6973,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, return; } - if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) { + if (captureArgs.captureSecureLayers && !hasCaptureBlackoutContentPermission()) { ALOGD("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT"); invokeScreenCaptureError(PERMISSION_DENIED, captureListener); return; @@ -7121,7 +6999,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, reqSize = display->getLayerStackSpaceRect().getSize(); } - for (const auto& handle : args.excludeHandles) { + for (const auto& handle : captureArgs.excludeHandles) { uint32_t excludeLayer = LayerHandle::getLayerId(handle); if (excludeLayer != UNASSIGNED_LAYER_ID) { excludeLayerIds.emplace(excludeLayer); @@ -7134,17 +7012,21 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, } GetLayerSnapshotsFunction getLayerSnapshotsFn = - getLayerSnapshotsForScreenshots(layerStack, args.uid, std::move(excludeLayerIds)); + getLayerSnapshotsForScreenshots(layerStack, captureArgs.uid, + std::move(excludeLayerIds)); ftl::Flags<RenderArea::Options> options; - if (args.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS; - if (args.hintForSeamlessTransition) + if (captureArgs.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS; + if (captureArgs.hintForSeamlessTransition) options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION; captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>, - args.sourceCrop, reqSize, args.dataspace, + gui::aidl_utils::fromARect(captureArgs.sourceCrop), + reqSize, + static_cast<ui::Dataspace>(captureArgs.dataspace), displayWeak, options), - getLayerSnapshotsFn, reqSize, args.pixelFormat, args.allowProtected, - args.grayscale, captureListener); + getLayerSnapshotsFn, reqSize, + static_cast<ui::PixelFormat>(captureArgs.pixelFormat), + captureArgs.allowProtected, captureArgs.grayscale, captureListener); } void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args, @@ -7197,10 +7079,11 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args if (args.hintForSeamlessTransition) options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION; captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>, - Rect(), size, args.dataspace, displayWeak, - options), - getLayerSnapshotsFn, size, args.pixelFormat, kAllowProtected, kGrayscale, - captureListener); + Rect(), size, + static_cast<ui::Dataspace>(args.dataspace), + displayWeak, options), + getLayerSnapshotsFn, size, static_cast<ui::PixelFormat>(args.pixelFormat), + kAllowProtected, kGrayscale, captureListener); } ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) { @@ -7213,20 +7096,23 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); - status_t validate = validateScreenshotPermissions(args); + const auto& captureArgs = args.captureArgs; + + status_t validate = validateScreenshotPermissions(captureArgs); if (validate != OK) { ALOGD("Permission denied to captureLayers"); invokeScreenCaptureError(validate, captureListener); return; } + auto crop = gui::aidl_utils::fromARect(captureArgs.sourceCrop); + ui::Size reqSize; sp<Layer> parent; - Rect crop(args.sourceCrop); std::unordered_set<uint32_t> excludeLayerIds; - ui::Dataspace dataspace = args.dataspace; + ui::Dataspace dataspace = static_cast<ui::Dataspace>(captureArgs.dataspace); - if (args.captureSecureLayers && !hasCaptureBlackoutContentPermission()) { + if (captureArgs.captureSecureLayers && !hasCaptureBlackoutContentPermission()) { ALOGD("Attempting to capture secure layers without CAPTURE_BLACKOUT_CONTENT"); invokeScreenCaptureError(PERMISSION_DENIED, captureListener); return; @@ -7243,26 +7129,27 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState()); - if (args.sourceCrop.width() <= 0) { + if (crop.width() <= 0) { crop.left = 0; crop.right = parentSourceBounds.getWidth(); } - if (args.sourceCrop.height() <= 0) { + if (crop.height() <= 0) { crop.top = 0; crop.bottom = parentSourceBounds.getHeight(); } - if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) { + if (crop.isEmpty() || captureArgs.frameScaleX <= 0.0f || captureArgs.frameScaleY <= 0.0f) { // Error out if the layer has no source bounds (i.e. they are boundless) and a source // crop was not specified, or an invalid frame scale was provided. ALOGD("Boundless layer, unspecified crop, or invalid frame scale to captureLayers"); invokeScreenCaptureError(BAD_VALUE, captureListener); return; } - reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY); + reqSize = ui::Size(crop.width() * captureArgs.frameScaleX, + crop.height() * captureArgs.frameScaleY); - for (const auto& handle : args.excludeHandles) { + for (const auto& handle : captureArgs.excludeHandles) { uint32_t excludeLayer = LayerHandle::getLayerId(handle); if (excludeLayer != UNASSIGNED_LAYER_ID) { excludeLayerIds.emplace(excludeLayer); @@ -7288,8 +7175,9 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } GetLayerSnapshotsFunction getLayerSnapshotsFn = - getLayerSnapshotsForScreenshots(parent->sequence, args.uid, std::move(excludeLayerIds), - args.childrenOnly, parentCrop); + getLayerSnapshotsForScreenshots(parent->sequence, captureArgs.uid, + std::move(excludeLayerIds), args.childrenOnly, + parentCrop); if (captureListener == nullptr) { ALOGD("capture screen must provide a capture listener callback"); @@ -7298,14 +7186,15 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, } ftl::Flags<RenderArea::Options> options; - if (args.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS; - if (args.hintForSeamlessTransition) + if (captureArgs.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS; + if (captureArgs.hintForSeamlessTransition) options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION; captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<LayerRenderAreaBuilder>, crop, reqSize, dataspace, parent, args.childrenOnly, options), - getLayerSnapshotsFn, reqSize, args.pixelFormat, args.allowProtected, - args.grayscale, captureListener); + getLayerSnapshotsFn, reqSize, + static_cast<ui::PixelFormat>(captureArgs.pixelFormat), + captureArgs.allowProtected, captureArgs.grayscale, captureListener); } // Creates a Future release fence for a layer and keeps track of it in a list to @@ -7971,7 +7860,6 @@ void SurfaceFlinger::onLayerFirstRef(Layer* layer) { void SurfaceFlinger::onLayerDestroyed(Layer* layer) { mNumLayers--; - removeHierarchyFromOffscreenLayers(layer); if (!layer->isRemovedFromCurrentState()) { mScheduler->deregisterLayer(layer); } @@ -7985,24 +7873,6 @@ void SurfaceFlinger::onLayerUpdate() { scheduleCommit(FrameHint::kActive); } -// WARNING: ONLY CALL THIS FROM LAYER DTOR -// Here we add children in the current state to offscreen layers and remove the -// layer itself from the offscreen layer list. Since -// this is the dtor, it is safe to access the current state. This keeps us -// from dangling children layers such that they are not reachable from the -// Drawing state nor the offscreen layer list -// See b/141111965 -void SurfaceFlinger::removeHierarchyFromOffscreenLayers(Layer* layer) { - for (auto& child : layer->getCurrentChildren()) { - mOffscreenLayers.emplace(child.get()); - } - mOffscreenLayers.erase(layer); -} - -void SurfaceFlinger::removeFromOffscreenLayers(Layer* layer) { - mOffscreenLayers.erase(layer); -} - status_t SurfaceFlinger::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { @@ -8174,20 +8044,6 @@ void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, Vs } else { parent->addChild(layer); } - - ui::LayerStack layerStack = layer->getLayerStack(LayerVector::StateSet::Current); - sp<const DisplayDevice> hintDisplay; - // Find the display that includes the layer. - for (const auto& [token, display] : mDisplays) { - if (display->getLayerStack() == layerStack) { - hintDisplay = display; - break; - } - } - - if (hintDisplay) { - layer->updateTransformHint(hintDisplay->getTransformHint()); - } } void SurfaceFlinger::sample() { @@ -8232,8 +8088,6 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD mActiveDisplayId = activeDisplay.getPhysicalId(); activeDisplay.getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true); - mScheduler->resetPhaseConfiguration(mDisplayModeController.getActiveMode(mActiveDisplayId).fps); - // TODO(b/255635711): Check for pending mode changes on other displays. mScheduler->setModeChangePending(false); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 94648223f3..873fac2c89 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -292,9 +292,6 @@ public: void onLayerDestroyed(Layer*); void onLayerUpdate(); - void removeHierarchyFromOffscreenLayers(Layer* layer); - void removeFromOffscreenLayers(Layer* layer); - // Called when all clients have released all their references to // this layer. The layer may still be kept alive by its parents but // the client can no longer modify this layer directly. @@ -824,8 +821,6 @@ private: // Clears and returns the masked bits. uint32_t clearTransactionFlags(uint32_t mask); - void commitOffscreenLayers(); - static LatchUnsignaledConfig getLatchUnsignaledConfig(); bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const; bool applyTransactionsLocked(std::vector<TransactionState>& transactions, VsyncId) @@ -1144,7 +1139,6 @@ private: void dumpHwc(std::string& result) const; perfetto::protos::LayersProto dumpProtoFromMainThread( uint32_t traceFlags = LayerTracing::TRACE_ALL) EXCLUDES(mStateLock); - void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock); void dumpPlannerInfo(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock); status_t doDump(int fd, const DumpArgs& args, bool asProto); @@ -1390,12 +1384,6 @@ private: // Flag used to set override desired display mode from backdoor bool mDebugDisplayModeSetByBackdoor = false; - // A set of layers that have no parent so they are not drawn on screen. - // Should only be accessed by the main thread. - // The Layer pointer is removed from the set when the destructor is called so there shouldn't - // be any issues with a raw pointer referencing an invalid object. - std::unordered_set<Layer*> mOffscreenLayers; - BufferCountTracker mBufferCountTracker; std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index 881bf35b58..c6856aea75 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -149,6 +149,13 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& handle->transformHint, handle->currentMaxAcquiredBufferCount, eventStats, handle->previousReleaseCallbackId); + if (handle->bufferReleaseChannel && + handle->previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) { + mBufferReleases.emplace_back(handle->bufferReleaseChannel, + handle->previousReleaseCallbackId, + handle->previousReleaseFence, + handle->currentMaxAcquiredBufferCount); + } } return NO_ERROR; } @@ -158,6 +165,12 @@ void TransactionCallbackInvoker::addPresentFence(sp<Fence> presentFence) { } void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) { + for (const auto& bufferRelease : mBufferReleases) { + bufferRelease.channel->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence, + bufferRelease.currentMaxAcquiredBufferCount); + } + mBufferReleases.clear(); + // For each listener auto completedTransactionsItr = mCompletedTransactions.begin(); ftl::SmallVector<ListenerStats, 10> listenerStatsToSend; diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 7853a9f359..14a7487156 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -16,18 +16,14 @@ #pragma once -#include <condition_variable> #include <deque> -#include <mutex> #include <optional> -#include <queue> -#include <thread> #include <unordered_map> -#include <unordered_set> #include <android-base/thread_annotations.h> #include <binder/IBinder.h> #include <ftl/future.h> +#include <gui/BufferReleaseChannel.h> #include <gui/ITransactionCompletedListener.h> #include <ui/Fence.h> #include <ui/FenceResult.h> @@ -59,6 +55,7 @@ public: uint64_t frameNumber = 0; uint64_t previousFrameNumber = 0; ReleaseCallbackId previousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; + std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel; }; class TransactionCallbackInvoker { @@ -86,6 +83,14 @@ private: std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash> mCompletedTransactions; + struct BufferRelease { + std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> channel; + ReleaseCallbackId callbackId; + sp<Fence> fence; + uint32_t currentMaxAcquiredBufferCount; + }; + std::vector<BufferRelease> mBufferReleases; + sp<Fence> mPresentFence; }; diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index a56bb513bd..07c720f670 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -119,6 +119,7 @@ void FlagManager::dump(std::string& result) const { DUMP_READ_ONLY_FLAG(connected_display); DUMP_READ_ONLY_FLAG(enable_small_area_detection); DUMP_READ_ONLY_FLAG(frame_rate_category_mrr); + DUMP_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr); DUMP_READ_ONLY_FLAG(misc1); DUMP_READ_ONLY_FLAG(vrr_config); DUMP_READ_ONLY_FLAG(hotplug2); @@ -222,6 +223,8 @@ FLAG_MANAGER_LEGACY_SERVER_FLAG(use_skia_tracing, PROPERTY_SKIA_ATRACE_ENABLED, FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "") FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "") FLAG_MANAGER_READ_ONLY_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr") +FLAG_MANAGER_READ_ONLY_FLAG(view_set_requested_frame_rate_mrr, + "debug.sf.view_set_requested_frame_rate_mrr") FLAG_MANAGER_READ_ONLY_FLAG(misc1, "") FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config") FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "") diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index 879929503b..a4b4a2b9f1 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -56,6 +56,7 @@ public: /// Trunk stable readonly flags /// bool connected_display() const; bool frame_rate_category_mrr() const; + bool view_set_requested_frame_rate_mrr() const; bool enable_small_area_detection() const; bool misc1() const; bool vrr_config() const; diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index 919ec178bd..886167e9f2 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -126,6 +126,14 @@ flag { } # override_trusted_overlay flag { + name: "view_set_requested_frame_rate_mrr" + namespace: "core_graphics" + description: "Enable to use frame rate category NoPreference with fixed frame rate vote on MRR devices" + bug: "352206100" + is_fixed_read_only: true +} # view_set_requested_frame_rate_mrr + +flag { name: "vrr_bugfix_24q4" namespace: "core_graphics" description: "bug fixes for VRR" diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp index 4f41a81011..222642f50c 100644 --- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp +++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> #include <private/gui/ComposerServiceAIDL.h> diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp index d74bd55987..efab7b856a 100644 --- a/services/surfaceflinger/tests/BufferGenerator.cpp +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -42,8 +42,13 @@ public: * through saved callback. */ class BufferListener : public ConsumerBase::FrameAvailableListener { public: +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + BufferListener(sp<BufferItemConsumer> consumer, BufferCallback callback) +#else BufferListener(sp<IGraphicBufferConsumer> consumer, BufferCallback callback) - : mConsumer(consumer), mCallback(callback) {} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + : mConsumer(consumer), mCallback(callback) { + } void onFrameAvailable(const BufferItem& /*item*/) { BufferItem item; @@ -55,7 +60,11 @@ public: } private: +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<BufferItemConsumer> mConsumer; +#else sp<IGraphicBufferConsumer> mConsumer; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) BufferCallback mCallback; }; @@ -63,6 +72,16 @@ public: * queue. */ void initialize(uint32_t width, uint32_t height, android_pixel_format_t format, BufferCallback callback) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + mBufferItemConsumer = sp<BufferItemConsumer>::make(GraphicBuffer::USAGE_HW_TEXTURE); + mBufferItemConsumer->setDefaultBufferSize(width, height); + mBufferItemConsumer->setDefaultBufferFormat(format); + + mListener = sp<BufferListener>::make(mBufferItemConsumer, callback); + mBufferItemConsumer->setFrameAvailableListener(mListener); + + mSurface = mBufferItemConsumer->getSurface(); +#else sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer); @@ -77,6 +96,7 @@ public: mBufferItemConsumer->setFrameAvailableListener(mListener); mSurface = sp<Surface>::make(producer, true); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) } /* Used by Egl manager. The surface is never displayed. */ diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index d355e720d1..e6fed63d96 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -20,7 +20,7 @@ #include <android/gui/ISurfaceComposer.h> #include <gtest/gtest.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/android_filesystem_config.h> @@ -280,7 +280,7 @@ TEST_F(CredentialsTest, CaptureLayersTest) { std::function<status_t()> condition = [=, this]() { LayerCaptureArgs captureArgs; captureArgs.layerHandle = mBGSurfaceControl->getHandle(); - captureArgs.sourceCrop = {0, 0, 1, 1}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(0, 0, 1, 1); ScreenCaptureResults captureResults; return ScreenCapture::captureLayers(captureArgs, captureResults); diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index 15a98df275..cc57e11206 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -28,66 +28,6 @@ using gui::ScreenCaptureResults; namespace test { -TEST(LayerStateTest, ParcellingDisplayCaptureArgs) { - DisplayCaptureArgs args; - args.pixelFormat = ui::PixelFormat::RGB_565; - args.sourceCrop = Rect(0, 0, 500, 200); - args.frameScaleX = 2; - args.frameScaleY = 4; - args.captureSecureLayers = true; - args.displayToken = sp<BBinder>::make(); - args.width = 10; - args.height = 20; - args.grayscale = true; - - Parcel p; - args.writeToParcel(&p); - p.setDataPosition(0); - - DisplayCaptureArgs args2; - args2.readFromParcel(&p); - - ASSERT_EQ(args.pixelFormat, args2.pixelFormat); - ASSERT_EQ(args.sourceCrop, args2.sourceCrop); - ASSERT_EQ(args.frameScaleX, args2.frameScaleX); - ASSERT_EQ(args.frameScaleY, args2.frameScaleY); - ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers); - ASSERT_EQ(args.displayToken, args2.displayToken); - ASSERT_EQ(args.width, args2.width); - ASSERT_EQ(args.height, args2.height); - ASSERT_EQ(args.grayscale, args2.grayscale); -} - -TEST(LayerStateTest, ParcellingLayerCaptureArgs) { - LayerCaptureArgs args; - args.pixelFormat = ui::PixelFormat::RGB_565; - args.sourceCrop = Rect(0, 0, 500, 200); - args.frameScaleX = 2; - args.frameScaleY = 4; - args.captureSecureLayers = true; - args.layerHandle = sp<BBinder>::make(); - args.excludeHandles = {sp<BBinder>::make(), sp<BBinder>::make()}; - args.childrenOnly = false; - args.grayscale = true; - - Parcel p; - args.writeToParcel(&p); - p.setDataPosition(0); - - LayerCaptureArgs args2; - args2.readFromParcel(&p); - - ASSERT_EQ(args.pixelFormat, args2.pixelFormat); - ASSERT_EQ(args.sourceCrop, args2.sourceCrop); - ASSERT_EQ(args.frameScaleX, args2.frameScaleX); - ASSERT_EQ(args.frameScaleY, args2.frameScaleY); - ASSERT_EQ(args.captureSecureLayers, args2.captureSecureLayers); - ASSERT_EQ(args.layerHandle, args2.layerHandle); - ASSERT_EQ(args.excludeHandles, args2.excludeHandles); - ASSERT_EQ(args.childrenOnly, args2.childrenOnly); - ASSERT_EQ(args.grayscale, args2.grayscale); -} - TEST(LayerStateTest, ParcellingScreenCaptureResultsWithFence) { ScreenCaptureResults results; results.buffer = sp<GraphicBuffer>::make(100u, 200u, PIXEL_FORMAT_RGBA_8888, 1u, 0u); diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 5b056d0765..03f900526d 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -23,7 +23,7 @@ #include <cutils/properties.h> #include <gtest/gtest.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp index f9b4bbac22..76bae4116c 100644 --- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp @@ -18,6 +18,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#include <gui/AidlUtil.h> #include <gui/BufferItemConsumer.h> #include <private/android_filesystem_config.h> #include "TransactionTestHarnesses.h" @@ -64,7 +65,7 @@ TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) { // only layerB is in this range LayerCaptureArgs captureArgs; captureArgs.layerHandle = parent->getHandle(); - captureArgs.sourceCrop = {0, 0, 32, 32}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(32, 32); ScreenCapture::captureLayers(&screenshot, captureArgs); screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); } diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index d97d433160..6cc1c51cde 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -20,6 +20,7 @@ #include <android-base/properties.h> #include <common/FlagManager.h> +#include <gui/AidlUtil.h> #include <private/android_filesystem_config.h> #include "LayerTransactionTest.h" #include "utils/TransactionUtils.h" @@ -350,7 +351,7 @@ TEST_F(MirrorLayerTest, OffscreenMirrorScreenshot) { // Capture just the mirror layer and child. LayerCaptureArgs captureArgs; captureArgs.layerHandle = mirrorParent->getHandle(); - captureArgs.sourceCrop = childBounds; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(childBounds); std::unique_ptr<ScreenCapture> shot; ScreenCapture::captureLayers(&shot, captureArgs); shot->expectSize(childBounds.width(), childBounds.height()); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 9a78550d00..c62f493941 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -20,6 +20,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#include <gui/AidlUtil.h> #include <private/android_filesystem_config.h> #include <ui/DisplayState.h> @@ -65,7 +66,7 @@ protected: .show(mFGSurfaceControl); }); - mCaptureArgs.sourceCrop = mDisplayRect; + mCaptureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(mDisplayRect); mCaptureArgs.layerHandle = mRootSurfaceControl->getHandle(); } @@ -112,7 +113,7 @@ TEST_F(ScreenCaptureTest, SetFlagsSecureEUidSystem) { shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK); } - mCaptureArgs.captureSecureLayers = true; + mCaptureArgs.captureArgs.captureSecureLayers = true; // AID_SYSTEM is allowed to capture secure content. ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_TRUE(mCaptureResults.capturedSecureLayers); @@ -164,7 +165,7 @@ TEST_F(ScreenCaptureTest, CaptureChildSetParentFlagsSecureEUidSystem) { // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able // to receive them...we are expected to take care with the results. - mCaptureArgs.captureSecureLayers = true; + mCaptureArgs.captureArgs.captureSecureLayers = true; ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_TRUE(mCaptureResults.capturedSecureLayers); ScreenCapture sc(mCaptureResults.buffer, mCaptureResults.capturedHdrLayers); @@ -198,8 +199,8 @@ TEST_F(ScreenCaptureTest, CaptureChildRespectsParentSecureFlag) { .apply(); LayerCaptureArgs captureArgs; captureArgs.layerHandle = childLayer->getHandle(); - captureArgs.sourceCrop = size; - captureArgs.captureSecureLayers = false; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(size); + captureArgs.captureArgs.captureSecureLayers = false; { SCOPED_TRACE("parent hidden"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -208,7 +209,7 @@ TEST_F(ScreenCaptureTest, CaptureChildRespectsParentSecureFlag) { sc.expectColor(size, Color::BLACK); } - captureArgs.captureSecureLayers = true; + captureArgs.captureArgs.captureSecureLayers = true; { SCOPED_TRACE("capture secure parent not visible"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -218,7 +219,7 @@ TEST_F(ScreenCaptureTest, CaptureChildRespectsParentSecureFlag) { } Transaction().show(parentLayer).apply(); - captureArgs.captureSecureLayers = false; + captureArgs.captureArgs.captureSecureLayers = false; { SCOPED_TRACE("parent visible"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -227,7 +228,7 @@ TEST_F(ScreenCaptureTest, CaptureChildRespectsParentSecureFlag) { sc.expectColor(size, Color::BLACK); } - captureArgs.captureSecureLayers = true; + captureArgs.captureArgs.captureSecureLayers = true; { SCOPED_TRACE("capture secure parent visible"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -259,8 +260,8 @@ TEST_F(ScreenCaptureTest, CaptureOffscreenChildRespectsParentSecureFlag) { .apply(); LayerCaptureArgs captureArgs; captureArgs.layerHandle = childLayer->getHandle(); - captureArgs.sourceCrop = size; - captureArgs.captureSecureLayers = false; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(size); + captureArgs.captureArgs.captureSecureLayers = false; { SCOPED_TRACE("parent hidden"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -269,7 +270,7 @@ TEST_F(ScreenCaptureTest, CaptureOffscreenChildRespectsParentSecureFlag) { sc.expectColor(size, Color::BLACK); } - captureArgs.captureSecureLayers = true; + captureArgs.captureArgs.captureSecureLayers = true; { SCOPED_TRACE("capture secure parent not visible"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -279,7 +280,7 @@ TEST_F(ScreenCaptureTest, CaptureOffscreenChildRespectsParentSecureFlag) { } Transaction().show(parentLayer).apply(); - captureArgs.captureSecureLayers = false; + captureArgs.captureArgs.captureSecureLayers = false; { SCOPED_TRACE("parent visible"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -288,7 +289,7 @@ TEST_F(ScreenCaptureTest, CaptureOffscreenChildRespectsParentSecureFlag) { sc.expectColor(size, Color::BLACK); } - captureArgs.captureSecureLayers = true; + captureArgs.captureArgs.captureSecureLayers = true; { SCOPED_TRACE("capture secure parent visible"); ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(captureArgs, mCaptureResults)); @@ -361,14 +362,14 @@ TEST_F(ScreenCaptureTest, CaptureLayerExclude) { LayerCaptureArgs captureArgs; captureArgs.layerHandle = fgHandle; captureArgs.childrenOnly = true; - captureArgs.excludeHandles = {child2->getHandle()}; + captureArgs.captureArgs.excludeHandles = {child2->getHandle()}; ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->checkPixel(10, 10, 0, 0, 0); mCapture->checkPixel(0, 0, 200, 200, 200); } TEST_F(ScreenCaptureTest, CaptureLayerExcludeThroughDisplayArgs) { - mCaptureArgs.excludeHandles = {mFGSurfaceControl->getHandle()}; + mCaptureArgs.captureArgs.excludeHandles = {mFGSurfaceControl->getHandle()}; ScreenCapture::captureLayers(&mCapture, mCaptureArgs); mCapture->expectBGColor(0, 0); // Doesn't capture FG layer which is at 64, 64 @@ -401,7 +402,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) { LayerCaptureArgs captureArgs; captureArgs.layerHandle = fgHandle; captureArgs.childrenOnly = true; - captureArgs.excludeHandles = {child2->getHandle()}; + captureArgs.captureArgs.excludeHandles = {child2->getHandle()}; ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->checkPixel(10, 10, 0, 0, 0); mCapture->checkPixel(0, 0, 200, 200, 200); @@ -418,7 +419,7 @@ TEST_F(ScreenCaptureTest, CaptureTransparent) { // Captures child LayerCaptureArgs captureArgs; captureArgs.layerHandle = child->getHandle(); - captureArgs.sourceCrop = {0, 0, 10, 20}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(10, 20); ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255}); // Area outside of child's bounds is transparent. @@ -481,7 +482,7 @@ TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithSourceCrop) { LayerCaptureArgs captureArgs; captureArgs.layerHandle = child->getHandle(); - captureArgs.sourceCrop = {0, 0, 10, 10}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(10, 10); ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect(0, 0, 9, 9), Color::RED); @@ -623,7 +624,7 @@ TEST_F(ScreenCaptureTest, CaptureCrop) { // red area to the right of the blue area mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED); - captureArgs.sourceCrop = {0, 0, 30, 30}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(30, 30); ScreenCapture::captureLayers(&mCapture, captureArgs); // Capturing the cropped screen, cropping out the shown red area, should leave only the blue // area visible. @@ -658,8 +659,8 @@ TEST_F(ScreenCaptureTest, CaptureSize) { // red area to the right of the blue area mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED); - captureArgs.frameScaleX = 0.5f; - captureArgs.frameScaleY = 0.5f; + captureArgs.captureArgs.frameScaleX = 0.5f; + captureArgs.captureArgs.frameScaleY = 0.5f; sleep(1); ScreenCapture::captureLayers(&mCapture, captureArgs); @@ -689,8 +690,8 @@ TEST_F(ScreenCaptureTest, CaptureTooLargeLayer) { LayerCaptureArgs captureArgs; captureArgs.layerHandle = redLayer->getHandle(); - captureArgs.frameScaleX = INT32_MAX / 60; - captureArgs.frameScaleY = INT32_MAX / 60; + captureArgs.captureArgs.frameScaleX = INT32_MAX / 60; + captureArgs.captureArgs.frameScaleY = INT32_MAX / 60; ScreenCaptureResults captureResults; ASSERT_EQ(BAD_VALUE, ScreenCapture::captureLayers(captureArgs, captureResults)); @@ -736,7 +737,7 @@ TEST_F(ScreenCaptureTest, CaptureSecureLayer) { mCapture->expectColor(Rect(30, 30, 60, 60), Color::RED); // Passing flag secure so the blue layer should be screenshot too. - args.captureSecureLayers = true; + args.captureArgs.captureSecureLayers = true; ScreenCapture::captureLayers(&mCapture, args); mCapture->expectColor(Rect(0, 0, 30, 30), Color::BLUE); mCapture->expectColor(Rect(30, 30, 60, 60), Color::RED); @@ -780,7 +781,7 @@ TEST_F(ScreenCaptureTest, ScreenshotProtectedBuffer) { // Reading color data will expectedly result in crash, only check usage bit // b/309965549 Checking that the usage bit is protected does not work for // devices that do not support usage protected. - mCaptureArgs.allowProtected = true; + mCaptureArgs.captureArgs.allowProtected = true; ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, captureResults)); // ASSERT_EQ(GRALLOC_USAGE_PROTECTED, GRALLOC_USAGE_PROTECTED & // captureResults.buffer->getUsage()); @@ -898,7 +899,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithUid) { // Make screenshot request with current uid set. No layers were created with the current // uid so screenshot will be black. - captureArgs.uid = fakeUid; + captureArgs.captureArgs.uid = fakeUid; ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect(0, 0, 32, 32), Color::TRANSPARENT); mCapture->expectBorder(Rect(0, 0, 32, 32), Color::TRANSPARENT); @@ -935,7 +936,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithUid) { mCapture->expectBorder(Rect(128, 128, 160, 160), Color::TRANSPARENT); // Screenshot from the fakeUid caller with no uid requested allows everything to be screenshot. - captureArgs.uid = -1; + captureArgs.captureArgs.uid = -1; ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect(128, 128, 160, 160), Color::RED); mCapture->expectBorder(Rect(128, 128, 160, 160), {63, 63, 195, 255}); @@ -955,7 +956,7 @@ TEST_F(ScreenCaptureTest, CaptureWithGrayscale) { ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect(0, 0, 32, 32), Color::RED); - captureArgs.grayscale = true; + captureArgs.captureArgs.grayscale = true; const uint8_t tolerance = 1; @@ -1052,7 +1053,7 @@ TEST_F(ScreenCaptureTest, captureOffscreenNullSnapshot) { LayerCaptureArgs captureArgs; captureArgs.layerHandle = mirroredLayer->getHandle(); - captureArgs.sourceCrop = Rect(0, 0, 1, 1); + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(1, 1); // Screenshot path should only use the children of the layer hierarchy so // that it will not create a new snapshot. A snapshot would otherwise be diff --git a/services/surfaceflinger/tests/TextureFiltering_test.cpp b/services/surfaceflinger/tests/TextureFiltering_test.cpp index c5d118c1aa..3f39cf6eea 100644 --- a/services/surfaceflinger/tests/TextureFiltering_test.cpp +++ b/services/surfaceflinger/tests/TextureFiltering_test.cpp @@ -14,9 +14,10 @@ * limitations under the License. */ +#include <android/gui/DisplayCaptureArgs.h> #include <android/gui/ISurfaceComposerClient.h> #include <gtest/gtest.h> -#include <gui/DisplayCaptureArgs.h> +#include <gui/AidlUtil.h> #include <ui/GraphicTypes.h> #include <ui/Rect.h> @@ -84,7 +85,7 @@ protected: }; TEST_F(TextureFilteringTest, NoFiltering) { - captureArgs.sourceCrop = Rect{0, 0, 100, 100}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(100, 100); captureArgs.layerHandle = mParent->getHandle(); ScreenCapture::captureLayers(&mCapture, captureArgs); @@ -93,7 +94,7 @@ TEST_F(TextureFilteringTest, NoFiltering) { } TEST_F(TextureFilteringTest, BufferCropNoFiltering) { - captureArgs.sourceCrop = Rect{0, 0, 100, 100}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(100, 100); captureArgs.layerHandle = mParent->getHandle(); ScreenCapture::captureLayers(&mCapture, captureArgs); @@ -105,7 +106,7 @@ TEST_F(TextureFilteringTest, BufferCropNoFiltering) { TEST_F(TextureFilteringTest, BufferCropIsFiltered) { Transaction().setBufferCrop(mLayer, Rect{25, 25, 75, 75}).apply(); - captureArgs.sourceCrop = Rect{0, 0, 100, 100}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(100, 100); captureArgs.layerHandle = mParent->getHandle(); ScreenCapture::captureLayers(&mCapture, captureArgs); @@ -114,9 +115,9 @@ TEST_F(TextureFilteringTest, BufferCropIsFiltered) { // Expect filtering because the output source crop is stretched to the output buffer's size. TEST_F(TextureFilteringTest, OutputSourceCropIsFiltered) { - captureArgs.frameScaleX = 2; - captureArgs.frameScaleY = 2; - captureArgs.sourceCrop = Rect{25, 25, 75, 75}; + captureArgs.captureArgs.frameScaleX = 2; + captureArgs.captureArgs.frameScaleY = 2; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(25, 25, 75, 75); captureArgs.layerHandle = mParent->getHandle(); ScreenCapture::captureLayers(&mCapture, captureArgs); @@ -127,9 +128,9 @@ TEST_F(TextureFilteringTest, OutputSourceCropIsFiltered) { // buffer's size. TEST_F(TextureFilteringTest, LayerCropOutputSourceCropIsFiltered) { Transaction().setCrop(mLayer, Rect{25, 25, 75, 75}).apply(); - captureArgs.frameScaleX = 2; - captureArgs.frameScaleY = 2; - captureArgs.sourceCrop = Rect{25, 25, 75, 75}; + captureArgs.captureArgs.frameScaleX = 2; + captureArgs.captureArgs.frameScaleY = 2; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(25, 25, 75, 75); captureArgs.layerHandle = mParent->getHandle(); ScreenCapture::captureLayers(&mCapture, captureArgs); @@ -139,8 +140,8 @@ TEST_F(TextureFilteringTest, LayerCropOutputSourceCropIsFiltered) { // Expect filtering because the layer is scaled up. TEST_F(TextureFilteringTest, LayerCaptureWithScalingIsFiltered) { captureArgs.layerHandle = mLayer->getHandle(); - captureArgs.frameScaleX = 2; - captureArgs.frameScaleY = 2; + captureArgs.captureArgs.frameScaleX = 2; + captureArgs.captureArgs.frameScaleY = 2; ScreenCapture::captureLayers(&mCapture, captureArgs); expectFiltered({0, 0, 100, 200}, {100, 0, 200, 200}); @@ -149,7 +150,7 @@ TEST_F(TextureFilteringTest, LayerCaptureWithScalingIsFiltered) { // Expect no filtering because the output buffer's size matches the source crop. TEST_F(TextureFilteringTest, LayerCaptureOutputSourceCropNoFiltering) { captureArgs.layerHandle = mLayer->getHandle(); - captureArgs.sourceCrop = Rect{25, 25, 75, 75}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(25, 25, 75, 75); ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED); @@ -162,7 +163,7 @@ TEST_F(TextureFilteringTest, LayerCaptureWithCropNoFiltering) { Transaction().setCrop(mLayer, Rect{10, 10, 90, 90}).apply(); captureArgs.layerHandle = mLayer->getHandle(); - captureArgs.sourceCrop = Rect{25, 25, 75, 75}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(25, 25, 75, 75); ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED); @@ -172,7 +173,7 @@ TEST_F(TextureFilteringTest, LayerCaptureWithCropNoFiltering) { // Expect no filtering because the output source crop and output buffer are the same size. TEST_F(TextureFilteringTest, OutputSourceCropDisplayFrameMatchNoFiltering) { captureArgs.layerHandle = mLayer->getHandle(); - captureArgs.sourceCrop = Rect{25, 25, 75, 75}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(25, 25, 75, 75); ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED); @@ -206,7 +207,7 @@ TEST_F(TextureFilteringTest, ParentHasTransformNoFiltering) { Transaction().setPosition(mParent, 100, 100).apply(); captureArgs.layerHandle = mParent->getHandle(); - captureArgs.sourceCrop = Rect{0, 0, 100, 100}; + captureArgs.captureArgs.sourceCrop = gui::aidl_utils::toARect(100, 100); ScreenCapture::captureLayers(&mCapture, captureArgs); mCapture->expectColor(Rect{0, 0, 50, 100}, Color::RED); diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index af3cb9aec1..67a524799d 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -16,6 +16,7 @@ #ifndef ANDROID_TRANSACTION_TEST_HARNESSES #define ANDROID_TRANSACTION_TEST_HARNESSES +#include <com_android_graphics_libgui_flags.h> #include <common/FlagManager.h> #include <ui/DisplayState.h> @@ -51,6 +52,16 @@ public: const ui::Size& resolution = displayMode.resolution; sp<IBinder> vDisplay; + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp<BufferItemConsumer> itemConsumer = sp<BufferItemConsumer>::make( + // Sample usage bits from screenrecord + GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_SW_READ_OFTEN); + sp<BufferListener> listener = sp<BufferListener>::make(this); + itemConsumer->setFrameAvailableListener(listener); + itemConsumer->setName(String8("Virtual disp consumer")); + itemConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); +#else sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; sp<BufferItemConsumer> itemConsumer; @@ -65,6 +76,7 @@ public: GRALLOC_USAGE_SW_READ_OFTEN); sp<BufferListener> listener = sp<BufferListener>::make(this); itemConsumer->setFrameAvailableListener(listener); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) static const std::string kDisplayName("VirtualDisplay"); vDisplay = SurfaceComposerClient::createVirtualDisplay(kDisplayName, @@ -76,7 +88,12 @@ public: SurfaceComposerClient::getDefault()->mirrorDisplay(displayId); SurfaceComposerClient::Transaction t; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + t.setDisplaySurface(vDisplay, + itemConsumer->getSurface()->getIGraphicBufferProducer()); +#else t.setDisplaySurface(vDisplay, producer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) t.setDisplayProjection(vDisplay, displayState.orientation, Rect(displayState.layerStackSpaceRect), Rect(resolution)); if (FlagManager::getInstance().ce_fence_promise()) { diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp index cd66dd20bb..d69378cec2 100644 --- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp +++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp @@ -27,6 +27,12 @@ namespace { class VirtualDisplayTest : public ::testing::Test { protected: void SetUp() override { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + mGLConsumer = sp<GLConsumer>::make(GLConsumer::TEXTURE_EXTERNAL, true, false, false); + mGLConsumer->setName(String8("Virtual disp consumer")); + mGLConsumer->setDefaultBufferSize(100, 100); + mProducer = mGLConsumer->getSurface()->getIGraphicBufferProducer(); +#else sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&mProducer, &consumer); @@ -34,6 +40,7 @@ protected: consumer->setDefaultBufferSize(100, 100); mGLConsumer = sp<GLConsumer>::make(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) } sp<IGraphicBufferProducer> mProducer; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp index 52bb07aca3..7e84408f7d 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -892,6 +892,50 @@ TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitCategory) { EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); } +TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithFixedSourceAndNoPreferenceCategory) { + SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); + SET_FLAG_FOR_TEST(flags::view_set_requested_frame_rate_mrr, true); + + auto layer = createLegacyAndFrontedEndLayer(1); + setFrameRate(1, (45.6_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + updateLayerSnapshotsAndLayerHistory(time); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + // There are 2 LayerRequirement's due to the frame rate category. + ASSERT_EQ(2u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + // First LayerRequirement is the layer's category specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::NoPreference, summarizeLayerHistory(time)[0].frameRateCategory); + + // Second LayerRequirement is the frame rate specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + summarizeLayerHistory(time)[1].vote); + EXPECT_EQ(45.6_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[1].frameRateCategory); + + // layer became infrequent, but the vote stays + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(2u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::NoPreference, summarizeLayerHistory(time)[0].frameRateCategory); +} + TEST_F(LayerHistoryIntegrationTest, multipleLayers) { auto layer1 = createLegacyAndFrontedEndLayer(1); auto layer2 = createLegacyAndFrontedEndLayer(2); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp index db6df229d5..4bc134fae8 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "LibSurfaceFlingerUnittests" #include <gtest/gtest.h> -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <private/gui/ComposerService.h> #include <private/gui/ComposerServiceAIDL.h> diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 184dada32e..e380e19797 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -180,6 +180,8 @@ public: MOCK_METHOD1(onHotplugDisconnect, void(Display)); MOCK_METHOD(Error, setRefreshRateChangedCallbackDebugEnabled, (Display, bool)); MOCK_METHOD(Error, notifyExpectedPresent, (Display, nsecs_t, int32_t)); + MOCK_METHOD(Error, getDisplayLuts, + (Display, std::vector<aidl::android::hardware::graphics::composer3::Lut>*)); }; } // namespace Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 602bdfc152..1eda3586c5 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -109,6 +109,8 @@ public: MOCK_METHOD(hal::Error, getOverlaySupport, (aidl::android::hardware::graphics::composer3::OverlayProperties *), (const override)); + MOCK_METHOD(hal::Error, getDisplayLuts, + (std::vector<aidl::android::hardware::graphics::composer3::Lut>*), (override)); }; class Layer : public HWC2::Layer { diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index 1675584f5a..0bedcd174e 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -15,7 +15,7 @@ */ #pragma once -#include <gui/AidlStatusUtil.h> +#include <gui/AidlUtil.h> #include <gui/SyncScreenCaptureListener.h> #include <private/gui/ComposerServiceAIDL.h> #include <ui/FenceResult.h> @@ -39,7 +39,7 @@ public: const auto sf = ComposerServiceAIDL::getComposerService(); SurfaceComposerClient::Transaction().apply(true); - captureArgs.dataspace = ui::Dataspace::V0_SRGB; + captureArgs.captureArgs.dataspace = static_cast<int32_t>(ui::Dataspace::V0_SRGB); const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make(); binder::Status status = sf->captureDisplay(captureArgs, captureListener); status_t err = statusTFromBinderStatus(status); @@ -77,7 +77,7 @@ public: const auto sf = ComposerServiceAIDL::getComposerService(); SurfaceComposerClient::Transaction().apply(true); - captureArgs.dataspace = ui::Dataspace::V0_SRGB; + captureArgs.captureArgs.dataspace = static_cast<int32_t>(ui::Dataspace::V0_SRGB); const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make(); binder::Status status = sf->captureLayers(captureArgs, captureListener); status_t err = statusTFromBinderStatus(status); diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp index c97f4014eb..3d8124b81b 100644 --- a/services/vibratorservice/VibratorHalWrapper.cpp +++ b/services/vibratorservice/VibratorHalWrapper.cpp @@ -32,6 +32,8 @@ using aidl::android::hardware::vibrator::CompositePrimitive; using aidl::android::hardware::vibrator::Effect; using aidl::android::hardware::vibrator::EffectStrength; using aidl::android::hardware::vibrator::PrimitivePwle; +using aidl::android::hardware::vibrator::PwleV2OutputMapEntry; +using aidl::android::hardware::vibrator::PwleV2Primitive; using aidl::android::hardware::vibrator::VendorEffect; using std::chrono::milliseconds; @@ -114,6 +116,12 @@ HalResult<void> HalWrapper::performPwleEffect(const std::vector<PrimitivePwle>&, return HalResult<void>::unsupported(); } +HalResult<void> HalWrapper::composePwleV2(const std::vector<PwleV2Primitive>&, + const std::function<void()>&) { + ALOGV("Skipped composePwleV2 because it's not available in Vibrator HAL"); + return HalResult<void>::unsupported(); +} + HalResult<Capabilities> HalWrapper::getCapabilities() { std::lock_guard<std::mutex> lock(mInfoMutex); if (mInfoCache.mCapabilities.isFailed()) { @@ -313,6 +321,13 @@ HalResult<void> AidlHalWrapper::performPwleEffect(const std::vector<PrimitivePwl return HalResultFactory::fromStatus(getHal()->composePwle(primitives, cb)); } +HalResult<void> AidlHalWrapper::composePwleV2(const std::vector<PwleV2Primitive>& composite, + const std::function<void()>& completionCallback) { + // This method should always support callbacks, so no need to double check. + auto cb = ndk::SharedRefBase::make<HalCallbackWrapper>(completionCallback); + return HalResultFactory::fromStatus(getHal()->composePwleV2(composite, cb)); +} + HalResult<Capabilities> AidlHalWrapper::getCapabilitiesInternal() { int32_t cap = 0; auto status = getHal()->getCapabilities(&cap); diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h index 20979bdcd8..ae0d9ab411 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h +++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h @@ -354,6 +354,8 @@ public: using CompositeEffect = aidl::android::hardware::vibrator::CompositeEffect; using Braking = aidl::android::hardware::vibrator::Braking; using PrimitivePwle = aidl::android::hardware::vibrator::PrimitivePwle; + using PwleV2Primitive = aidl::android::hardware::vibrator::PwleV2Primitive; + using PwleV2OutputMapEntry = aidl::android::hardware::vibrator::PwleV2OutputMapEntry; explicit HalWrapper(std::shared_ptr<CallbackScheduler> scheduler) : mCallbackScheduler(std::move(scheduler)) {} @@ -391,6 +393,9 @@ public: virtual HalResult<void> performPwleEffect(const std::vector<PrimitivePwle>& primitives, const std::function<void()>& completionCallback); + virtual HalResult<void> composePwleV2(const std::vector<PwleV2Primitive>& composite, + const std::function<void()>& completionCallback); + protected: // Shared pointer to allow CallbackScheduler to outlive this wrapper. const std::shared_ptr<CallbackScheduler> mCallbackScheduler; @@ -471,6 +476,9 @@ public: const std::vector<PrimitivePwle>& primitives, const std::function<void()>& completionCallback) override final; + HalResult<void> composePwleV2(const std::vector<PwleV2Primitive>& composite, + const std::function<void()>& completionCallback) override final; + protected: HalResult<Capabilities> getCapabilitiesInternal() override final; HalResult<std::vector<Effect>> getSupportedEffectsInternal() override final; diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp index 7bcc59ac01..ba7e1f07bf 100644 --- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp @@ -39,6 +39,7 @@ using aidl::android::hardware::vibrator::EffectStrength; using aidl::android::hardware::vibrator::IVibrator; using aidl::android::hardware::vibrator::IVibratorCallback; using aidl::android::hardware::vibrator::PrimitivePwle; +using aidl::android::hardware::vibrator::PwleV2Primitive; using aidl::android::hardware::vibrator::VendorEffect; using aidl::android::os::PersistableBundle; @@ -681,3 +682,38 @@ TEST_F(VibratorHalWrapperAidlTest, TestPerformPwleEffect) { ASSERT_TRUE(result.isOk()); ASSERT_EQ(1, *callbackCounter.get()); } + +TEST_F(VibratorHalWrapperAidlTest, TestComposePwleV2) { + auto pwleEffect = { + PwleV2Primitive(/*amplitude=*/0.2, /*frequency=*/50, /*time=*/100), + PwleV2Primitive(/*amplitude=*/0.5, /*frequency=*/150, /*time=*/100), + PwleV2Primitive(/*amplitude=*/0.8, /*frequency=*/250, /*time=*/100), + }; + + { + InSequence seq; + EXPECT_CALL(*mMockHal.get(), composePwleV2(_, _)) + .Times(Exactly(3)) + .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION))) + .WillOnce(Return(ndk::ScopedAStatus::fromExceptionCode(EX_SECURITY))) + .WillOnce(DoAll(WithArg<1>(vibrator::TriggerCallback()), + Return(ndk::ScopedAStatus::ok()))); + } + + std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); + auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); + + auto result = mWrapper->composePwleV2(pwleEffect, callback); + ASSERT_TRUE(result.isUnsupported()); + // Callback not triggered on failure + ASSERT_EQ(0, *callbackCounter.get()); + + result = mWrapper->composePwleV2(pwleEffect, callback); + ASSERT_TRUE(result.isFailed()); + // Callback not triggered for unsupported + ASSERT_EQ(0, *callbackCounter.get()); + + result = mWrapper->composePwleV2(pwleEffect, callback); + ASSERT_TRUE(result.isOk()); + ASSERT_EQ(1, *callbackCounter.get()); +} diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp index 9a7c69d0d1..83430d79a5 100644 --- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp +++ b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp @@ -40,6 +40,7 @@ using aidl::android::hardware::vibrator::Effect; using aidl::android::hardware::vibrator::EffectStrength; using aidl::android::hardware::vibrator::IVibrator; using aidl::android::hardware::vibrator::PrimitivePwle; +using aidl::android::hardware::vibrator::PwleV2Primitive; using aidl::android::hardware::vibrator::VendorEffect; using aidl::android::os::PersistableBundle; @@ -369,3 +370,19 @@ TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformPwleEffectUnsupported) { // No callback is triggered. ASSERT_EQ(0, *callbackCounter.get()); } + +TEST_F(VibratorHalWrapperHidlV1_0Test, TestComposePwleV2Unsupported) { + auto pwleEffect = { + PwleV2Primitive(/*amplitude=*/0.2, /*frequency=*/50, /*time=*/100), + PwleV2Primitive(/*amplitude=*/0.5, /*frequency=*/150, /*time=*/100), + PwleV2Primitive(/*amplitude=*/0.8, /*frequency=*/250, /*time=*/100), + }; + + std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>(); + auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get()); + + ASSERT_TRUE(mWrapper->composePwleV2(pwleEffect, callback).isUnsupported()); + + // No callback is triggered. + ASSERT_EQ(0, *callbackCounter.get()); +} diff --git a/services/vibratorservice/test/test_mocks.h b/services/vibratorservice/test/test_mocks.h index 2f9451e1ae..5e090849af 100644 --- a/services/vibratorservice/test/test_mocks.h +++ b/services/vibratorservice/test/test_mocks.h @@ -41,6 +41,8 @@ using aidl::android::hardware::vibrator::EffectStrength; using aidl::android::hardware::vibrator::IVibrator; using aidl::android::hardware::vibrator::IVibratorCallback; using aidl::android::hardware::vibrator::PrimitivePwle; +using aidl::android::hardware::vibrator::PwleV2OutputMapEntry; +using aidl::android::hardware::vibrator::PwleV2Primitive; using aidl::android::hardware::vibrator::VendorEffect; // ------------------------------------------------------------------------------------------------- @@ -89,6 +91,17 @@ public: MOCK_METHOD(ndk::ScopedAStatus, getPwlePrimitiveDurationMax, (int32_t * ret), (override)); MOCK_METHOD(ndk::ScopedAStatus, getPwleCompositionSizeMax, (int32_t * ret), (override)); MOCK_METHOD(ndk::ScopedAStatus, getSupportedBraking, (std::vector<Braking> * ret), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getPwleV2FrequencyToOutputAccelerationMap, + (std::vector<PwleV2OutputMapEntry> * ret), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getPwleV2PrimitiveDurationMaxMillis, (int32_t* ret), + (override)); + MOCK_METHOD(ndk::ScopedAStatus, getPwleV2PrimitiveDurationMinMillis, (int32_t* ret), + (override)); + MOCK_METHOD(ndk::ScopedAStatus, getPwleV2CompositionSizeMax, (int32_t* ret), (override)); + MOCK_METHOD(ndk::ScopedAStatus, composePwleV2, + (const std::vector<PwleV2Primitive>& e, + const std::shared_ptr<IVibratorCallback>& cb), + (override)); MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t*), (override)); MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string*), (override)); MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override)); diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 00e987fb2e..ba2b8887bc 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1215,8 +1215,15 @@ VkResult GetPhysicalDeviceSurfaceFormats2KHR( surfaceCompressionProps ->imageCompressionFixedRateFlags = compressionProps.imageCompressionFixedRateFlags; - } else { + } else if (compressionRes == + VK_ERROR_OUT_OF_HOST_MEMORY || + compressionRes == + VK_ERROR_OUT_OF_DEVICE_MEMORY) { return compressionRes; + } else { + // For any of the *_NOT_SUPPORTED errors we continue + // onto the next format + continue; } } } break; |