diff options
26 files changed, 422 insertions, 48 deletions
diff --git a/Android.bp b/Android.bp index 2520a71968..119c7ea5a4 100644 --- a/Android.bp +++ b/Android.bp @@ -119,3 +119,9 @@ filegroup { srcs: ["aidl/android/hardware/display/IDeviceProductInfoConstants.aidl"], path: "aidl", } + +dirgroup { + name: "trusty_dirgroup_frameworks_native", + dirs: ["libs/binder"], + visibility: ["//trusty/vendor/google/aosp/scripts"], +} diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp index 6f7fea3432..ce7c55c7b3 100644 --- a/cmds/dumpstate/DumpstateInternal.cpp +++ b/cmds/dumpstate/DumpstateInternal.cpp @@ -108,7 +108,7 @@ bool DropRootUser() { const uint32_t cap_syslog_mask = CAP_TO_MASK(CAP_SYSLOG); const uint32_t cap_syslog_index = CAP_TO_INDEX(CAP_SYSLOG); - bool has_cap_syslog = (capdata[cap_syslog_index].effective & cap_syslog_mask) != 0; + bool has_cap_syslog = (capdata[cap_syslog_index].permitted & cap_syslog_mask) != 0; memset(&capdata, 0, sizeof(capdata)); if (has_cap_syslog) { diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 52b485a6f6..98a7555a4c 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -39,10 +39,14 @@ static const char* kStaticCachableList[] = { "account", "activity", "alarm", + "android.frameworks.stats.IStats/default", "android.system.keystore2.IKeystoreService/default", "appops", "audio", + "autofill", + "batteryproperties", "batterystats", + "biometic", "carrier_config", "connectivity", "content", @@ -58,6 +62,7 @@ static const char* kStaticCachableList[] = { "jobscheduler", "legacy_permission", "location", + "lock_settings", "media.extractor", "media.metrics", "media.player", @@ -78,15 +83,19 @@ static const char* kStaticCachableList[] = { "phone", "platform_compat", "power", + "processinfo", "role", + "sensitive_content_protection_service", "sensorservice", "statscompanion", "telephony.registry", "thermalservice", "time_detector", + "tracing.proxy", "trust", "uimode", "user", + "vibrator", "virtualdevice", "virtualdevice_native", "webviewupdate", @@ -114,11 +123,30 @@ binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serv if (!kUseCache) { return binder::Status::ok(); } + std::string traceStr; + if (atrace_is_tag_enabled(ATRACE_TAG_AIDL)) { + traceStr = "BinderCacheWithInvalidation::updateCache : " + serviceName; + } + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, traceStr.c_str()); + if (service.getTag() == os::Service::Tag::binder) { sp<IBinder> binder = service.get<os::Service::Tag::binder>(); - if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) && - binder->isBinderAlive()) { + if (!binder) { + binder::ScopedTrace + aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache failed: binder_null"); + } else if (!binder->isBinderAlive()) { + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache failed: " + "isBinderAlive_false"); + } else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) { + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache successful"); return mCacheForGetService->setItem(serviceName, binder); + } else { + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::updateCache failed: " + "caching_not_enabled"); } } return binder::Status::ok(); diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h index 47b2ec9f2c..feb8470032 100644 --- a/libs/binder/BackendUnifiedServiceManager.h +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -18,6 +18,7 @@ #include <android/os/BnServiceManager.h> #include <android/os/IServiceManager.h> #include <binder/IPCThreadState.h> +#include <binder/Trace.h> #include <map> #include <memory> @@ -59,6 +60,12 @@ public: } bool removeItem(const std::string& key, const sp<IBinder>& who) { + std::string traceStr; + uint64_t tag = ATRACE_TAG_AIDL; + if (atrace_is_tag_enabled(tag)) { + traceStr = "BinderCacheWithInvalidation::removeItem " + key; + } + binder::ScopedTrace aidlTrace(tag, traceStr.c_str()); std::lock_guard<std::mutex> lock(mCacheMutex); if (auto it = mCache.find(key); it != mCache.end()) { if (it->second.service == who) { @@ -81,11 +88,22 @@ public: if (item->localBinder() == nullptr) { status_t status = item->linkToDeath(deathRecipient); if (status != android::OK) { + std::string traceStr; + uint64_t tag = ATRACE_TAG_AIDL; + if (atrace_is_tag_enabled(tag)) { + traceStr = + "BinderCacheWithInvalidation::setItem Failed LinkToDeath for service " + + key + " : " + std::to_string(status); + } + binder::ScopedTrace aidlTrace(tag, traceStr.c_str()); + ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(), status); return binder::Status::fromStatusT(status); } } + binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, + "BinderCacheWithInvalidation::setItem Successfully Cached"); std::lock_guard<std::mutex> lock(mCacheMutex); Entry entry = {.service = item, .deathRecipient = deathRecipient}; mCache[key] = entry; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index eae844ca03..3758b6521c 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -197,7 +197,9 @@ sp<BpBinder> BpBinder::create(int32_t handle, std::function<void()>* postTask) { && currentValue < sBinderProxyCountHighWatermark && ((trackedValue & WARNING_REACHED_MASK) == 0)) [[unlikely]] { sTrackingMap[trackedUid] |= WARNING_REACHED_MASK; - if (sWarningCallback) sWarningCallback(trackedUid); + if (sWarningCallback) { + *postTask = [=]() { sWarningCallback(trackedUid); }; + } } else if (currentValue >= sBinderProxyCountHighWatermark) { ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)", getuid(), trackedUid, trackedValue); diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 95a5da20ae..ab449572d6 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -94,6 +94,9 @@ }, { "name": "libbinder_rpc_unstable_bindgen_test" + }, + { + "name": "binderCacheUnitTest" } ], "presubmit-large": [ @@ -133,9 +136,6 @@ { "name": "binder_sdk_test", "host": true - }, - { - "name": "binderCacheUnitTest" } ], "imports": [ diff --git a/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl index 75f87530f9..9bac38641e 100644 --- a/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl +++ b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl @@ -16,6 +16,8 @@ package android.content.pm; +import android.content.pm.StagedApexInfo; + /** * This event is designed for notification to native code listener about * any changes to set of apex packages staged for installation on next boot. @@ -23,5 +25,5 @@ package android.content.pm; * @hide */ parcelable ApexStagedEvent { - @utf8InCpp String[] stagedApexModuleNames; + StagedApexInfo[] stagedApexInfos; } diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 3ddfefa311..0f0be2f22b 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -135,13 +135,7 @@ interface IPackageManagerNative { void unregisterStagedApexObserver(in IStagedApexObserver observer); /** - * Get APEX module names of all APEX that are staged ready for installation + * Get information of staged APEXes. */ - @utf8InCpp String[] getStagedApexModuleNames(); - - /** - * Get information of APEX which is staged ready for installation. - * Returns null if no such APEX is found. - */ - @nullable StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName); + StagedApexInfo[] getStagedApexInfos(); } diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl index 949835b452..8f7ad30779 100644 --- a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl +++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl @@ -22,6 +22,7 @@ package android.content.pm; * * @hide */ +@JavaDerive(equals=true) parcelable StagedApexInfo { @utf8InCpp String moduleName; @utf8InCpp String diskImagePath; diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h index c671eed039..0b4f196b8f 100644 --- a/libs/binder/include/binder/SafeInterface.h +++ b/libs/binder/include/binder/SafeInterface.h @@ -152,6 +152,14 @@ public: return callParcel("writeParcelableVector", [&]() { return parcel->writeParcelableVector(v); }); } + + status_t read(const Parcel& parcel, std::vector<bool>* v) const { + return callParcel("readBoolVector", [&]() { return parcel.readBoolVector(v); }); + } + status_t write(Parcel* parcel, const std::vector<bool>& v) const { + return callParcel("writeBoolVector", [&]() { return parcel->writeBoolVector(v); }); + } + status_t read(const Parcel& parcel, float* f) const { return callParcel("readFloat", [&]() { return parcel.readFloat(f); }); } diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 8b0dda33dd..28a3f654b8 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -731,6 +731,9 @@ cc_test { "liblog", "libutils", ], + static_libs: [ + "libgmock", + ], test_suites: [ "general-tests", "vts", diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index 0aa678dd65..849dc7c4d5 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -40,6 +40,8 @@ #include <sys/eventfd.h> #include <sys/prctl.h> +#include <gmock/gmock.h> + using namespace std::chrono_literals; // NOLINT - google-build-using-namespace using android::binder::unique_fd; @@ -222,6 +224,7 @@ public: SetDeathToken = IBinder::FIRST_CALL_TRANSACTION, ReturnsNoMemory, LogicalNot, + LogicalNotVector, ModifyEnum, IncrementFlattenable, IncrementLightFlattenable, @@ -249,6 +252,7 @@ public: // These are ordered according to their corresponding methods in SafeInterface::ParcelHandler virtual status_t logicalNot(bool a, bool* notA) const = 0; + virtual status_t logicalNot(const std::vector<bool>& a, std::vector<bool>* notA) const = 0; virtual status_t modifyEnum(TestEnum a, TestEnum* b) const = 0; virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0; virtual status_t increment(const TestLightFlattenable& a, @@ -288,7 +292,14 @@ public: } status_t logicalNot(bool a, bool* notA) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); - return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA); + using Signature = status_t (ISafeInterfaceTest::*)(bool, bool*) const; + return callRemote<Signature>(Tag::LogicalNot, a, notA); + } + status_t logicalNot(const std::vector<bool>& a, std::vector<bool>* notA) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + using Signature = status_t (ISafeInterfaceTest::*)(const std::vector<bool>&, + std::vector<bool>*) const; + return callRemote<Signature>(Tag::LogicalNotVector, a, notA); } status_t modifyEnum(TestEnum a, TestEnum* b) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); @@ -406,6 +417,14 @@ public: *notA = !a; return NO_ERROR; } + status_t logicalNot(const std::vector<bool>& a, std::vector<bool>* notA) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + notA->clear(); + for (bool value : a) { + notA->push_back(!value); + } + return NO_ERROR; + } status_t modifyEnum(TestEnum a, TestEnum* b) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); *b = (a == TestEnum::INITIAL) ? TestEnum::FINAL : TestEnum::INVALID; @@ -513,7 +532,13 @@ public: return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory); } case ISafeInterfaceTest::Tag::LogicalNot: { - return callLocal(data, reply, &ISafeInterfaceTest::logicalNot); + using Signature = status_t (ISafeInterfaceTest::*)(bool a, bool* notA) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::logicalNot); + } + case ISafeInterfaceTest::Tag::LogicalNotVector: { + using Signature = status_t (ISafeInterfaceTest::*)(const std::vector<bool>& a, + std::vector<bool>* notA) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::logicalNot); } case ISafeInterfaceTest::Tag::ModifyEnum: { return callLocal(data, reply, &ISafeInterfaceTest::modifyEnum); @@ -639,6 +664,15 @@ TEST_F(SafeInterfaceTest, TestLogicalNot) { ASSERT_EQ(!b, notB); } +TEST_F(SafeInterfaceTest, TestLogicalNotVector) { + const std::vector<bool> a = {true, false, true}; + std::vector<bool> notA; + status_t result = mSafeInterfaceTest->logicalNot(a, ¬A); + ASSERT_EQ(NO_ERROR, result); + std::vector<bool> expected = {false, true, false}; + ASSERT_THAT(notA, testing::ContainerEq(expected)); +} + TEST_F(SafeInterfaceTest, TestModifyEnum) { const TestEnum a = TestEnum::INITIAL; TestEnum b = TestEnum::INVALID; diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index 6880678050..656453411d 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -28,6 +28,7 @@ static constexpr int kWidth = 100; static constexpr int kHeight = 100; static constexpr int kMaxLockedBuffers = 3; static constexpr int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; +static constexpr int kUsage = GRALLOC_USAGE_SW_READ_RARELY; static constexpr int kFrameSleepUs = 30 * 1000; class BufferItemConsumerTest : public ::testing::Test { @@ -44,8 +45,7 @@ class BufferItemConsumerTest : public ::testing::Test { void SetUp() override { BufferQueue::createBufferQueue(&mProducer, &mConsumer); - mBIC = - new BufferItemConsumer(mConsumer, kFormat, kMaxLockedBuffers, true); + mBIC = new BufferItemConsumer(mConsumer, kUsage, kMaxLockedBuffers, true); String8 name("BufferItemConsumer_Under_Test"); mBIC->setName(name); mBFL = new BufferFreedListener(this); diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index 931c311e65..f19b908074 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -19,10 +19,9 @@ extern crate nativewindow_bindgen as ffi; mod handle; mod surface; -pub use handle::NativeHandle; -pub use surface::Surface; - pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; +pub use handle::NativeHandle; +pub use surface::{buffer::Buffer, Surface}; use binder::{ binder_impl::{BorrowedParcel, UnstructuredParcelable}, diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs index 9eddfcd497..ed52471aa1 100644 --- a/libs/nativewindow/rust/src/surface.rs +++ b/libs/nativewindow/rust/src/surface.rs @@ -14,6 +14,8 @@ //! Rust wrapper for `ANativeWindow` and related types. +pub(crate) mod buffer; + use binder::{ binder_impl::{BorrowedParcel, UnstructuredParcelable}, impl_deserialize_for_unstructured_parcelable, impl_serialize_for_unstructured_parcelable, @@ -21,17 +23,18 @@ use binder::{ StatusCode, }; use bitflags::bitflags; +use buffer::Buffer; use nativewindow_bindgen::{ ADataSpace, AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getBuffersDataSpace, ANativeWindow_getBuffersDefaultDataSpace, - ANativeWindow_getFormat, ANativeWindow_getHeight, ANativeWindow_getWidth, + ANativeWindow_getFormat, ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_lock, ANativeWindow_readFromParcel, ANativeWindow_release, ANativeWindow_setBuffersDataSpace, ANativeWindow_setBuffersGeometry, ANativeWindow_setBuffersTransform, - ANativeWindow_writeToParcel, + ANativeWindow_unlockAndPost, ANativeWindow_writeToParcel, ARect, }; use std::error::Error; use std::fmt::{self, Debug, Display, Formatter}; -use std::ptr::{null_mut, NonNull}; +use std::ptr::{self, null_mut, NonNull}; /// Wrapper around an opaque C `ANativeWindow`. #[derive(PartialEq, Eq)] @@ -153,6 +156,43 @@ impl Surface { Ok(ADataSpace(data_space)) } } + + /// Locks the window's next drawing surface for writing, and returns it. + pub fn lock(&mut self, bounds: Option<&mut ARect>) -> Result<Buffer, ErrorCode> { + let mut buffer = buffer::EMPTY; + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. The other pointers must be valid because the come from + // references, and aren't retained after the function returns. + let status = unsafe { + ANativeWindow_lock( + self.0.as_ptr(), + &mut buffer, + bounds.map(ptr::from_mut).unwrap_or(null_mut()), + ) + }; + if status != 0 { + return Err(ErrorCode(status)); + } + + Ok(Buffer::new(buffer, self)) + } + + /// Unlocks the window's drawing surface which was previously locked, posting the new buffer to + /// the display. + /// + /// This shouldn't be called directly but via the [`Buffer`], hence is not public here. + fn unlock_and_post(&mut self) -> Result<(), ErrorCode> { + // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because + // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel` + // and we have not yet released it. + let status = unsafe { ANativeWindow_unlockAndPost(self.0.as_ptr()) }; + if status == 0 { + Ok(()) + } else { + Err(ErrorCode(status)) + } + } } impl Drop for Surface { diff --git a/libs/nativewindow/rust/src/surface/buffer.rs b/libs/nativewindow/rust/src/surface/buffer.rs new file mode 100644 index 0000000000..a2d74d4ed6 --- /dev/null +++ b/libs/nativewindow/rust/src/surface/buffer.rs @@ -0,0 +1,68 @@ +// 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. + +use super::{ErrorCode, Surface}; +use nativewindow_bindgen::{AHardwareBuffer_Format, ANativeWindow_Buffer}; +use std::ptr::null_mut; + +/// An empty `ANativeWindow_Buffer`. +pub const EMPTY: ANativeWindow_Buffer = ANativeWindow_Buffer { + width: 0, + height: 0, + stride: 0, + format: 0, + bits: null_mut(), + reserved: [0; 6], +}; + +/// Rust wrapper for `ANativeWindow_Buffer`, representing a locked buffer from a [`Surface`]. +pub struct Buffer<'a> { + /// The wrapped `ANativeWindow_Buffer`. + pub buffer: ANativeWindow_Buffer, + surface: &'a mut Surface, +} + +impl<'a> Buffer<'a> { + pub(crate) fn new(buffer: ANativeWindow_Buffer, surface: &'a mut Surface) -> Self { + Self { buffer, surface } + } + + /// Unlocks the window's drawing surface which was previously locked to create this buffer, + /// posting the buffer to the display. + pub fn unlock_and_post(self) -> Result<(), ErrorCode> { + self.surface.unlock_and_post() + } + + /// The number of pixels that are shown horizontally. + pub fn width(&self) -> i32 { + self.buffer.width + } + + /// The number of pixels that are shown vertically. + pub fn height(&self) -> i32 { + self.buffer.height + } + + /// The number of pixels that a line in the buffer takes in memory. + /// + /// This may be greater than the width. + pub fn stride(&self) -> i32 { + self.buffer.stride + } + + /// The pixel format of the buffer. + pub fn format(&self) -> Result<AHardwareBuffer_Format::Type, ErrorCode> { + self.buffer.format.try_into().map_err(|_| ErrorCode(self.buffer.format)) + } +} diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h index 4a0889f596..568d348ba9 100644 --- a/services/inputflinger/dispatcher/CancelationOptions.h +++ b/services/inputflinger/dispatcher/CancelationOptions.h @@ -32,7 +32,8 @@ struct CancelationOptions { CANCEL_POINTER_EVENTS = 1, CANCEL_NON_POINTER_EVENTS = 2, CANCEL_FALLBACK_EVENTS = 3, - ftl_last = CANCEL_FALLBACK_EVENTS, + CANCEL_HOVER_EVENTS = 4, + ftl_last = CANCEL_HOVER_EVENTS }; // The criterion to use to determine which events should be canceled. diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 2161e0985b..7eb7e36386 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -746,7 +746,8 @@ std::vector<TouchedWindow> getHoveringWindowsLocked(const TouchState* oldState, } touchedWindow.dispatchMode = InputTarget::DispatchMode::AS_IS; } - touchedWindow.addHoveringPointer(entry.deviceId, pointer); + const auto [x, y] = resolveTouchedPosition(entry); + touchedWindow.addHoveringPointer(entry.deviceId, pointer, x, y); if (canReceiveForegroundTouches(*newWindow->getInfo())) { touchedWindow.targetFlags |= InputTarget::Flags::FOREGROUND; } @@ -873,6 +874,8 @@ std::pair<bool /*cancelPointers*/, bool /*cancelNonPointers*/> expandCancellatio return {false, true}; case CancelationOptions::Mode::CANCEL_FALLBACK_EVENTS: return {false, true}; + case CancelationOptions::Mode::CANCEL_HOVER_EVENTS: + return {true, false}; } } @@ -2511,7 +2514,8 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( if (isHoverAction) { // The "windowHandle" is the target of this hovering pointer. - tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointer); + tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointer, x, + y); } // Set target flags. @@ -5437,6 +5441,31 @@ void InputDispatcher::setInputWindowsLocked( } } + // Check if the hovering should stop because the window is no longer eligible to receive it + // (for example, if the touchable region changed) + if (const auto& it = mTouchStatesByDisplay.find(displayId); it != mTouchStatesByDisplay.end()) { + TouchState& state = it->second; + for (TouchedWindow& touchedWindow : state.windows) { + std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf( + [this, displayId, &touchedWindow](const PointerProperties& properties, float x, + float y) REQUIRES(mLock) { + const bool isStylus = properties.toolType == ToolType::STYLUS; + const ui::Transform displayTransform = getTransformLocked(displayId); + const bool stillAcceptsTouch = + windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(), + displayId, x, y, isStylus, displayTransform); + return !stillAcceptsTouch; + }); + + for (DeviceId deviceId : erasedDevices) { + CancelationOptions options(CancelationOptions::Mode::CANCEL_HOVER_EVENTS, + "WindowInfo changed", traceContext.getTracker()); + options.deviceId = deviceId; + synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options); + } + } + } + // Release information for windows that are no longer present. // This ensures that unused input channels are released promptly. // Otherwise, they might stick around until the window handle is destroyed diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index dfbe02f332..e283fc3b4d 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -638,6 +638,8 @@ bool InputState::shouldCancelMotion(const MotionMemento& memento, return memento.source & AINPUT_SOURCE_CLASS_POINTER; case CancelationOptions::Mode::CANCEL_NON_POINTER_EVENTS: return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); + case CancelationOptions::Mode::CANCEL_HOVER_EVENTS: + return memento.hovering; default: return false; } diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 0c9ad3c7b7..2bf63beb05 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -112,17 +112,18 @@ android::base::Result<void> TouchState::addOrUpdateWindow( } void TouchState::addHoveringPointerToWindow(const sp<WindowInfoHandle>& windowHandle, - DeviceId deviceId, const PointerProperties& pointer) { + DeviceId deviceId, const PointerProperties& pointer, + float x, float y) { for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.addHoveringPointer(deviceId, pointer); + touchedWindow.addHoveringPointer(deviceId, pointer, x, y); return; } } TouchedWindow touchedWindow; touchedWindow.windowHandle = windowHandle; - touchedWindow.addHoveringPointer(deviceId, pointer); + touchedWindow.addHoveringPointer(deviceId, pointer, x, y); windows.push_back(touchedWindow); } diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 9d4bb3d943..3fbe584a64 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -49,7 +49,8 @@ struct TouchState { DeviceId deviceId, const std::vector<PointerProperties>& touchingPointers, std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt); void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, - DeviceId deviceId, const PointerProperties& pointer); + DeviceId deviceId, const PointerProperties& pointer, float x, + float y); void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); void clearHoveringPointers(DeviceId deviceId); diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index 1f86f6635a..fa5be1a719 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -36,6 +36,13 @@ bool hasPointerId(const std::vector<PointerProperties>& pointers, int32_t pointe }) != pointers.end(); } +bool hasPointerId(const std::vector<TouchedWindow::HoveringPointer>& pointers, int32_t pointerId) { + return std::find_if(pointers.begin(), pointers.end(), + [&pointerId](const TouchedWindow::HoveringPointer& pointer) { + return pointer.properties.id == pointerId; + }) != pointers.end(); +} + } // namespace bool TouchedWindow::hasHoveringPointers() const { @@ -78,16 +85,18 @@ bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) con return hasPointerId(state.hoveringPointers, pointerId); } -void TouchedWindow::addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer) { - std::vector<PointerProperties>& hoveringPointers = mDeviceStates[deviceId].hoveringPointers; +void TouchedWindow::addHoveringPointer(DeviceId deviceId, const PointerProperties& properties, + float x, float y) { + std::vector<HoveringPointer>& hoveringPointers = mDeviceStates[deviceId].hoveringPointers; const size_t initialSize = hoveringPointers.size(); - std::erase_if(hoveringPointers, [&pointer](const PointerProperties& properties) { - return properties.id == pointer.id; + std::erase_if(hoveringPointers, [&properties](const HoveringPointer& pointer) { + return pointer.properties.id == properties.id; }); if (hoveringPointers.size() != initialSize) { - LOG(ERROR) << __func__ << ": " << pointer << ", device " << deviceId << " was in " << *this; + LOG(ERROR) << __func__ << ": " << properties << ", device " << deviceId << " was in " + << *this; } - hoveringPointers.push_back(pointer); + hoveringPointers.push_back({properties, x, y}); } Result<void> TouchedWindow::addTouchingPointers(DeviceId deviceId, @@ -173,8 +182,8 @@ bool TouchedWindow::hasActiveStylus() const { return true; } } - for (const PointerProperties& properties : state.hoveringPointers) { - if (properties.toolType == ToolType::STYLUS) { + for (const HoveringPointer& pointer : state.hoveringPointers) { + if (pointer.properties.toolType == ToolType::STYLUS) { return true; } } @@ -270,8 +279,8 @@ void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) } DeviceState& state = stateIt->second; - std::erase_if(state.hoveringPointers, [&pointerId](const PointerProperties& properties) { - return properties.id == pointerId; + std::erase_if(state.hoveringPointers, [&pointerId](const HoveringPointer& pointer) { + return pointer.properties.id == pointerId; }); if (!state.hasPointers()) { @@ -279,6 +288,22 @@ void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) } } +std::vector<DeviceId> TouchedWindow::eraseHoveringPointersIf( + std::function<bool(const PointerProperties&, float /*x*/, float /*y*/)> condition) { + std::vector<DeviceId> erasedDevices; + for (auto& [deviceId, state] : mDeviceStates) { + std::erase_if(state.hoveringPointers, [&](const HoveringPointer& pointer) { + if (condition(pointer.properties, pointer.x, pointer.y)) { + erasedDevices.push_back(deviceId); + return true; + } + return false; + }); + } + + return erasedDevices; +} + void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { @@ -312,6 +337,11 @@ std::string TouchedWindow::dump() const { return out; } +std::ostream& operator<<(std::ostream& out, const TouchedWindow::HoveringPointer& pointer) { + out << pointer.properties << " at (" << pointer.x << ", " << pointer.y << ")"; + return out; +} + std::ostream& operator<<(std::ostream& out, const TouchedWindow& window) { out << window.dump(); return out; diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 4f0ad1628a..c38681eef0 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -38,7 +38,7 @@ struct TouchedWindow { bool hasHoveringPointers() const; bool hasHoveringPointers(DeviceId deviceId) const; bool hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const; - void addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer); + void addHoveringPointer(DeviceId deviceId, const PointerProperties& pointer, float x, float y); void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); // Touching @@ -69,6 +69,15 @@ struct TouchedWindow { void clearHoveringPointers(DeviceId deviceId); std::string dump() const; + struct HoveringPointer { + PointerProperties properties; + float x; + float y; + }; + + std::vector<DeviceId> eraseHoveringPointersIf( + std::function<bool(const PointerProperties&, float /*x*/, float /*y*/)> condition); + private: struct DeviceState { std::vector<PointerProperties> touchingPointers; @@ -78,7 +87,7 @@ private: // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE // scenario. std::optional<nsecs_t> downTimeInTarget; - std::vector<PointerProperties> hoveringPointers; + std::vector<HoveringPointer> hoveringPointers; bool hasPointers() const { return !touchingPointers.empty() || !hoveringPointers.empty(); }; }; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 73ab0dae41..48930ef444 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1923,6 +1923,99 @@ TEST_F(InputDispatcherTest, HoverMoveAndScroll) { window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL)); } +/** + * Two windows: a trusted overlay and a regular window underneath. Both windows are visible. + * Mouse is hovered, and the hover event should only go to the overlay. + * However, next, the touchable region of the trusted overlay shrinks. The mouse position hasn't + * changed, but the cursor would now end up hovering above the regular window underneatch. + * If the mouse is now clicked, this would generate an ACTION_DOWN event, which would go to the + * regular window. However, the trusted overlay is also watching for outside touch. + * The trusted overlay should get two events: + * 1) The ACTION_OUTSIDE event, since the click is now not inside its touchable region + * 2) The HOVER_EXIT event, since the mouse pointer is no longer hovering inside this window + * + * This test reproduces a crash where there is an overlap between dispatch modes for the trusted + * overlay touch target, since the event is causing both an ACTION_OUTSIDE, and as a HOVER_EXIT. + */ +TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlay) { + std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay", + ui::LogicalDisplayId::DEFAULT); + overlay->setTrustedOverlay(true); + overlay->setWatchOutsideTouch(true); + overlay->setFrame(Rect(0, 0, 200, 200)); + + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window", + ui::LogicalDisplayId::DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); + // Hover the mouse into the overlay + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) + .build()); + overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have + // the regular window as the touch target + overlay->setTouchableRegion(Region({0, 0, 0, 0})); + mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); + + // Now we can click with the mouse. The click should go into the regular window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) + .build()); + overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + overlay->consumeMotionEvent(WithMotionAction(ACTION_OUTSIDE)); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); +} + +/** + * Similar to above, but also has a spy on top that also catches the HOVER + * events. Also, instead of ACTION_DOWN, we are continuing to send the hovering + * stream to ensure that the spy receives hover events correctly. + */ +TEST_F(InputDispatcherTest, MouseClickUnderShrinkingTrustedOverlayWithSpy) { + std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> spyWindow = + sp<FakeWindowHandle>::make(app, mDispatcher, "Spy", ui::LogicalDisplayId::DEFAULT); + spyWindow->setFrame(Rect(0, 0, 200, 200)); + spyWindow->setTrustedOverlay(true); + spyWindow->setSpy(true); + sp<FakeWindowHandle> overlay = sp<FakeWindowHandle>::make(app, mDispatcher, "Trusted overlay", + ui::LogicalDisplayId::DEFAULT); + overlay->setTrustedOverlay(true); + overlay->setWatchOutsideTouch(true); + overlay->setFrame(Rect(0, 0, 200, 200)); + + sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(app, mDispatcher, "Regular window", + ui::LogicalDisplayId::DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged( + {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); + // Hover the mouse into the overlay + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) + .build()); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + // Now, shrink the touchable region of the overlay! This will cause the cursor to suddenly have + // the regular window as the touch target + overlay->setTouchableRegion(Region({0, 0, 0, 0})); + mDispatcher->onWindowInfosChanged( + {{*spyWindow->getInfo(), *overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); + + // Now we can click with the mouse. The click should go into the regular window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) + .build()); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); + overlay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); +} + using InputDispatcherMultiDeviceTest = InputDispatcherTest; /** diff --git a/services/stats/Android.bp b/services/stats/Android.bp index 6b99627f5a..f698515545 100644 --- a/services/stats/Android.bp +++ b/services/stats/Android.bp @@ -7,6 +7,11 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +vintf_fragment { + name: "android.frameworks.stats-service.xml", + src: "android.frameworks.stats-service.xml", +} + cc_library_shared { name: "libstatshidl", srcs: [ @@ -38,7 +43,7 @@ cc_library_shared { local_include_dirs: [ "include/stats", ], - vintf_fragments: [ + vintf_fragment_modules: [ "android.frameworks.stats-service.xml", ], } diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index 0284192cc4..bfb7bd6d6f 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -1169,7 +1169,7 @@ inline Json::Value ArrayToJsonValue(uint32_t count, const T* values) { return array; } -template <typename T, unsigned int N> +template <typename T, size_t N> inline Json::Value ToJsonValue(const T (&value)[N]) { return ArrayToJsonValue(N, value); } @@ -1293,7 +1293,7 @@ inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) { return true; } -template <typename T, unsigned int N> +template <typename T, size_t N> inline bool AsValue(Json::Value* json_value, T (*value)[N]) { return AsArray(json_value, N, *value); } |