From 7aa71e7b6f224a55a0056664822c7b937be7c3f7 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 1 Apr 2019 15:34:32 -0700 Subject: gui: add hidl hybrid interface as libgui header dependency Bug: 129710438 Change-Id: I848a8c2f225920886883c23d5defd38fef5b8951 --- libs/gui/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libs') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 4c2e6532ff..a61e7e162b 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -15,6 +15,10 @@ cc_library_headers { name: "libgui_headers", vendor_available: true, export_include_dirs: ["include"], + + // we must build this module to get the required header as that is generated + export_shared_lib_headers: [ "android.hidl.token@1.0-utils" ], + shared_libs: [ "android.hidl.token@1.0-utils" ], } cc_library_shared { -- cgit v1.2.3-59-g8ed1b From 51d713f6cd804e00c57d4d1c37a61f9c1fd5fe25 Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Wed, 3 Apr 2019 17:25:57 -0700 Subject: Add OWNERS to libs/gui/bufferqueue Bug: None Test: None Change-Id: Id114a1e0f43ee03a3fe95e821d8264187132ddfa --- libs/gui/bufferqueue/OWNERS | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 libs/gui/bufferqueue/OWNERS (limited to 'libs') diff --git a/libs/gui/bufferqueue/OWNERS b/libs/gui/bufferqueue/OWNERS new file mode 100644 index 0000000000..cbe931707c --- /dev/null +++ b/libs/gui/bufferqueue/OWNERS @@ -0,0 +1,5 @@ +chz@google.com +lajos@google.com +pawin@google.com +taklee@google.com +wonsik@google.com -- cgit v1.2.3-59-g8ed1b From 1c403eef2013b0fe4c5ba32ccd48c80a1d3440ad Mon Sep 17 00:00:00 2001 From: Przemyslaw Szczepaniak Date: Thu, 4 Apr 2019 13:57:41 +0100 Subject: Remove PRODUCT_SERVICES from PackageManagerNative.getLocation. It's not used in next android release and its causing issues with cherry-picking to AOSP. Bug: 120483623 Test: Flashed crosshatch, NNAPI cts tests Change-Id: I651796b7f2a79b6236e01bf52d9a80927805f217 --- libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl | 3 --- 1 file changed, 3 deletions(-) (limited to 'libs') diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index b1c577ecd0..70ed80df85 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -66,15 +66,12 @@ interface IPackageManagerNative { const int LOCATION_VENDOR = 0x2; /* ApplicationInfo.isProduct() == true */ const int LOCATION_PRODUCT = 0x4; - /* ApplicationInfo.isProductServices() == true */ - const int LOCATION_PRODUCT_SERVICES = 0x8; /** * Returns a set of bitflags about package location. * LOCATION_SYSTEM: getApplicationInfo(packageName).isSystemApp() * LOCATION_VENDOR: getApplicationInfo(packageName).isVendor() * LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct() - * LOCATION_PRODUCT_SERVICES: getApplicationInfo(packageName).isProductService() */ int getLocationFlags(in @utf8InCpp String packageName); } -- cgit v1.2.3-59-g8ed1b From 30c8d907d48758caa3901de33450398571e5eace Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 4 Apr 2019 13:12:49 -0700 Subject: SurfaceComposerClient: Fix potential null de-reference in setRelativeLayer Obviously the code immediately following the diff was going to segfault if we didnt return. Looks like just a trivial refactoring error. Bug: 76148527 Test: Trivial. Change-Id: I0b575e0d8123d57d8110c9450c7a623c65bcd87c --- libs/gui/SurfaceComposerClient.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 83cf40c8e9..124eb7f007 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -620,6 +620,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelat layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eRelativeLayerChanged; s->relativeLayerHandle = relativeTo; -- cgit v1.2.3-59-g8ed1b From acec532d4c018cce542665b7a3f93d985437a5dd Mon Sep 17 00:00:00 2001 From: tangrobin Date: Thu, 21 Feb 2019 19:40:26 +0800 Subject: gui: add additional test for region sampling Add additional test that help verify the region sampling function. Bug: 119639245 Test: ./libgui_test --gtest_filter="RegionSamplingTest.*" Change-Id: Ie42b4cd5767b846f247781ab3b14a22ff9b7ad83 --- libs/gui/tests/RegionSampling_test.cpp | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'libs') diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index d33ecfbdb9..c9de37d957 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -297,4 +297,70 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { composer->removeRegionSamplingListener(grayListener); } +TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) { + sp composer = ComposerService::getComposerService(); + sp listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + // Invalid input sampleArea + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(), + listener)); + listener->reset(); + // Invalid input binder + EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener)); + // Invalid input listener + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL)); + EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL)); + // remove the listener + composer->removeRegionSamplingListener(listener); +} + +TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { + fill_render(rgba_green); + sp composer = ComposerService::getComposerService(); + sp listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + fill_render(rgba_green); + + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + + listener->reset(); + composer->removeRegionSamplingListener(listener); + fill_render(rgba_green); + EXPECT_FALSE(listener->wait_event(100ms)) + << "callback should stop after remove the region sampling listener"; +} + +TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { + sp composer = ComposerService::getComposerService(); + sp listener = new Listener(); + Rect sampleArea{100, 100, 200, 200}; + + // Test: listener in (100, 100). See layer before move, no layer after move. + fill_render(rgba_blue); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_blue, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + composer->removeRegionSamplingListener(listener); + + // Test: listener offset to (600, 600). No layer before move, see layer after move. + fill_render(rgba_green); + sampleArea.offsetTo(600, 600); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + composer->removeRegionSamplingListener(listener); +} + } // namespace android::test -- cgit v1.2.3-59-g8ed1b From c5f7a3a6130860f07db0f48ac9096493a7219f2c Mon Sep 17 00:00:00 2001 From: Marius Renn Date: Fri, 26 Apr 2019 10:16:38 -0700 Subject: Adds new HardwareBuffer plane-locking functions to NDK This mirrors the API added to libandroid to libnativewindow. Test: Run cts-tradefed run commandAndExit cts -m CtsNativeHardwareTestCases Bug: 131319526 Change-Id: I8b97cdf8e7348e0c00f4ec62cbeb471ea4e00795 --- libs/nativewindow/libnativewindow.map.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 23a05f3dca..bad8b11540 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -8,6 +8,7 @@ LIBNATIVEWINDOW { AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; AHardwareBuffer_lockAndGetInfo; # introduced=29 + AHardwareBuffer_lockPlanes; # introduced=29 AHardwareBuffer_recvHandleFromUnixSocket; AHardwareBuffer_release; AHardwareBuffer_sendHandleToUnixSocket; -- cgit v1.2.3-59-g8ed1b From d45fdc3420e498cd1e300d92697f860bed62c475 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Tue, 30 Apr 2019 06:14:19 -0700 Subject: SurfaceComposerClient: Fix potential null de-reference in detachChildren We return from the function when we know the pointer is null to avoid dereferencing it. Test: TreeHugger Change-Id: I487b71ba185a48b505719a14b38b8a60283e10a7 --- libs/gui/SurfaceComposerClient.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a0ed940d71..01bfe2adef 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1051,6 +1051,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachCh layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDetachChildren; -- cgit v1.2.3-59-g8ed1b From 0891c9b5b050e89a90585dd17ac4428e6ae56522 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 6 May 2019 15:05:13 -0700 Subject: binder: readCallingWorkSourceUid make const Bug: N/A Test: N/A Change-Id: I09ec79695efc05ca88884f7c43a6a7ca7353dfda --- libs/binder/Parcel.cpp | 2 +- libs/binder/include/binder/Parcel.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 5427ff8e4c..6d936147fd 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -628,7 +628,7 @@ bool Parcel::replaceCallingWorkSourceUid(uid_t uid) return err == NO_ERROR; } -uid_t Parcel::readCallingWorkSourceUid() +uid_t Parcel::readCallingWorkSourceUid() const { if (!mRequestHeaderPresent) { return IPCThreadState::kUnsetWorkSource; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index e5219a5590..cfee364b97 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -399,7 +399,7 @@ public: bool replaceCallingWorkSourceUid(uid_t uid); // Returns the work source provided by the caller. This can only be trusted for trusted calling // uid. - uid_t readCallingWorkSourceUid(); + uid_t readCallingWorkSourceUid() const; void readRequestHeaders() const; private: -- cgit v1.2.3-59-g8ed1b From f5e6c7e5fade7dd2b416c896b39fd1d4a23e8713 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 17 May 2019 13:14:06 -0700 Subject: libbinder: readCString: no ubsan sub-overflow Bug: 131859347 Test: fuzzer Change-Id: I95a0f59684a172925f1eab97ff21e5d14bc79cc8 --- libs/binder/Parcel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0c57335c89..580573e279 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2074,8 +2074,8 @@ status_t Parcel::readUtf8FromUtf16(std::unique_ptr* str) const { const char* Parcel::readCString() const { - const size_t avail = mDataSize-mDataPos; - if (avail > 0) { + if (mDataPos < mDataSize) { + const size_t avail = mDataSize-mDataPos; const char* str = reinterpret_cast(mData+mDataPos); // is the string's trailing NUL within the parcel's valid bounds? const char* eos = reinterpret_cast(memchr(str, 0, avail)); -- cgit v1.2.3-59-g8ed1b From 1eafe08a93cead5628f1f827be99528a51f4ca70 Mon Sep 17 00:00:00 2001 From: Tianyu Jiang Date: Tue, 21 May 2019 19:44:48 -0700 Subject: Reduce debug level log from libbufferhub Logs that indicates possible racing between consumers and producers of a buffer are removed because they are expected to race each other. Log that indicates possible racing in bufferhubd is moved from info level to verbose level. Test: vega runs without libbufferhub log spam Bug: 129544259 Change-Id: I9307602797ff9c1bbc774264682a83bf4ddd0240 (cherry picked from commit b9d077f9be584114c39ac8417452cd20817c0236) --- libs/vr/libbufferhub/consumer_buffer.cpp | 12 ------------ libs/vr/libbufferhub/producer_buffer.cpp | 16 ---------------- services/vr/bufferhubd/producer_channel.cpp | 2 +- 3 files changed, 1 insertion(+), 29 deletions(-) (limited to 'libs') diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp index 115e8666e5..7823e36d3d 100644 --- a/libs/vr/libbufferhub/consumer_buffer.cpp +++ b/libs/vr/libbufferhub/consumer_buffer.cpp @@ -52,12 +52,6 @@ int ConsumerBuffer::LocalAcquire(DvrNativeBufferMetadata* out_meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s Failed to acquire the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to acquire the buffer and modify the buffer state to " - "%" PRIx32 ". About to try again if the buffer is still posted.", - __FUNCTION__, current_buffer_state, updated_buffer_state); if (!BufferHubDefs::isClientPosted(current_buffer_state, client_state_mask())) { ALOGE( @@ -152,12 +146,6 @@ int ConsumerBuffer::LocalRelease(const DvrNativeBufferMetadata* meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to release the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to release the buffer and modify the buffer state to " - "%" PRIx32 ". About to try again.", - __FUNCTION__, current_buffer_state, updated_buffer_state); // The failure of compare_exchange_weak updates current_buffer_state. updated_buffer_state = current_buffer_state & (~client_state_mask()); } diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp index 3d88ba5dbe..aa9d07282b 100644 --- a/libs/vr/libbufferhub/producer_buffer.cpp +++ b/libs/vr/libbufferhub/producer_buffer.cpp @@ -96,13 +96,6 @@ int ProducerBuffer::LocalPost(const DvrNativeBufferMetadata* meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to post the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to post the buffer and modify the buffer state to " - "%" PRIx32 - ". About to try again if the buffer is still gained by this client.", - __FUNCTION__, current_buffer_state, updated_buffer_state); if (!BufferHubDefs::isClientGained(current_buffer_state, client_state_mask())) { ALOGE( @@ -186,15 +179,6 @@ int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to gain the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to gain the buffer and modify the buffer state to " - "%" PRIx32 - ". About to try again if the buffer is still not read by other " - "clients.", - __FUNCTION__, current_buffer_state, updated_buffer_state); - if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) || BufferHubDefs::isAnyClientGained(current_buffer_state) || (BufferHubDefs::isAnyClientPosted( diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index a7fd912294..b71964ba00 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -350,7 +350,7 @@ Status ProducerChannel::CreateConsumer( while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGI( + ALOGV( "%s: Failed to post to the new consumer. " "Current buffer state was changed to %" PRIx32 " when trying to acquire the buffer and modify the buffer state to " -- cgit v1.2.3-59-g8ed1b From dbf960d37ebae3b5c92f42c82a40086ff4c33c98 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 20 May 2019 15:28:13 -0700 Subject: libbinder: Status: check dataPosition sets. Bug: 132650049 Test: fuzzer Change-Id: Id230eae4316a444bc82b416b2049d5a5f589f89a --- libs/binder/Status.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp index 8b33a56484..0ad99cee3f 100644 --- a/libs/binder/Status.cpp +++ b/libs/binder/Status.cpp @@ -102,13 +102,23 @@ status_t Status::readFromParcel(const Parcel& parcel) { // Skip over fat response headers. Not used (or propagated) in native code. if (mException == EX_HAS_REPLY_HEADER) { // Note that the header size includes the 4 byte size field. - const int32_t header_start = parcel.dataPosition(); + const size_t header_start = parcel.dataPosition(); + // Get available size before reading more + const size_t header_avail = parcel.dataAvail(); + int32_t header_size; status = parcel.readInt32(&header_size); if (status != OK) { setFromStatusT(status); return status; } + + if (header_size < 0 || static_cast(header_size) > header_avail) { + android_errorWriteLog(0x534e4554, "132650049"); + setFromStatusT(UNKNOWN_ERROR); + return UNKNOWN_ERROR; + } + parcel.setDataPosition(header_start + header_size); // And fat response headers are currently only used when there are no // exceptions, so act like there was no error. @@ -135,19 +145,36 @@ status_t Status::readFromParcel(const Parcel& parcel) { setFromStatusT(status); return status; } + if (remote_stack_trace_header_size < 0 || + static_cast(remote_stack_trace_header_size) > parcel.dataAvail()) { + + android_errorWriteLog(0x534e4554, "132650049"); + setFromStatusT(UNKNOWN_ERROR); + return UNKNOWN_ERROR; + } parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size); if (mException == EX_SERVICE_SPECIFIC) { status = parcel.readInt32(&mErrorCode); } else if (mException == EX_PARCELABLE) { // Skip over the blob of Parcelable data - const int32_t header_start = parcel.dataPosition(); + const size_t header_start = parcel.dataPosition(); + // Get available size before reading more + const size_t header_avail = parcel.dataAvail(); + int32_t header_size; status = parcel.readInt32(&header_size); if (status != OK) { setFromStatusT(status); return status; } + + if (header_size < 0 || static_cast(header_size) > header_avail) { + android_errorWriteLog(0x534e4554, "132650049"); + setFromStatusT(UNKNOWN_ERROR); + return UNKNOWN_ERROR; + } + parcel.setDataPosition(header_start + header_size); } if (status != OK) { -- cgit v1.2.3-59-g8ed1b From f92661b58260a3a5901f733f43f8ac37e9ffc338 Mon Sep 17 00:00:00 2001 From: Yuichiro Hanada Date: Thu, 6 Jun 2019 18:50:18 +0900 Subject: Fix debug print when a KCM file is not found. Bug: None Test: m Change-Id: I6d5507dd227a46c73d82c7a2433d70c7dccdef21 --- libs/input/Keyboard.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'libs') diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index 0c22bfefed..56900c129e 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -38,29 +38,29 @@ KeyMap::KeyMap() { KeyMap::~KeyMap() { } -status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, +status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { - status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str()); + status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { - status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str()); + status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyCharacterMapName.string()); } } @@ -70,25 +70,25 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, } // Try searching by device identifier. - if (probeKeyMap(deviceIdenfifier, "")) { + if (probeKeyMap(deviceIdentifier, "")) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. - if (probeKeyMap(deviceIdenfifier, "Generic")) { + if (probeKeyMap(deviceIdentifier, "Generic")) { return OK; } // Try the Virtual key map as a last resort. - if (probeKeyMap(deviceIdenfifier, "Virtual")) { + if (probeKeyMap(deviceIdentifier, "Virtual")) { return OK; } // Give up! ALOGE("Could not determine key map for device '%s' and no default key maps were found!", - deviceIdenfifier.name.c_str()); + deviceIdentifier.name.c_str()); return NAME_NOT_FOUND; } -- cgit v1.2.3-59-g8ed1b From e8097ca7c5e00ed61d7f604d8eda8d2fe2d2fa9b Mon Sep 17 00:00:00 2001 From: chaviw Date: Fri, 7 Jun 2019 17:08:53 -0700 Subject: Remove SurfaceControl.destroy function The destroy function was only used temporarily instead of all call points calling reparent(null) explicitly. Removing the Java destroy request so no need for the SurfaceControl.destroy method anymore. Test: SurfaceControlTest Change-Id: If69e030f3babf83a6382f85a26f0bb1eb451dc23 --- libs/gui/SurfaceControl.cpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'libs') diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 55488dad0b..011854edbb 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -71,14 +71,6 @@ SurfaceControl::~SurfaceControl() release(); } -void SurfaceControl::destroy() -{ - if (isValid()) { - SurfaceComposerClient::Transaction().reparent(this, nullptr).apply(); - } - release(); -} - void SurfaceControl::release() { // Trigger an IPC now, to make sure things -- cgit v1.2.3-59-g8ed1b From 12536a8fdae818ec39ae274d7da561480f4e1d61 Mon Sep 17 00:00:00 2001 From: silence_dogood Date: Fri, 7 Jun 2019 15:00:32 -0700 Subject: Cache NATIVE_WINDOW_MAX_BUFFER_COUNT in Surface To avoid the sync binder call to BufferQueue everytime vkGetPhysicalDeviceSurfaceCapabilitiesKHR is called, we cache the NATIVE_WINDOW_MAX_BUFFER_COUNT at the Surface each time the client connects. Bug: 133187007 Test: Vulkan cts tests Change-Id: I1942ff75ceb539c4904dc98c2e488c4d4cade31d --- libs/gui/BufferQueueProducer.cpp | 1 + libs/gui/Surface.cpp | 6 ++++++ libs/gui/include/gui/IGraphicBufferProducer.h | 1 + libs/gui/include/gui/Surface.h | 1 + 4 files changed, 9 insertions(+) (limited to 'libs') diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..b005707fd2 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1199,6 +1199,7 @@ status_t BufferQueueProducer::connect(const sp& listener, static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; + output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..2e8a5d005b 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,6 +96,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; + mMaxBufferCount = 0; } Surface::~Surface() { @@ -961,6 +962,10 @@ int Surface::query(int what, int* value) const { *value = static_cast(mDataSpace); return NO_ERROR; } + case NATIVE_WINDOW_MAX_BUFFER_COUNT: { + *value = mMaxBufferCount; + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -1298,6 +1303,7 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; + mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..6e002dd505 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,6 +412,7 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; + int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..80469dfeaf 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -465,6 +465,7 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; + int mMaxBufferCount; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 621102e5d2c97bd00404817191fa5012749a7a0f Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 12 Jun 2019 14:16:57 -0700 Subject: Make SurfaceControl Transaction parcelable 2/2 Allow clients to send SurfaceControl Transactions across processes to enable more advanced synchronization use cases. Bug: 132205507 Test: atest SurfaceFlinger_test Change-Id: I20a33cafc0960e73f9a2c3d740f81319e02b68ff --- libs/gui/SurfaceComposerClient.cpp | 89 ++++++++++++++++++++++++++++ libs/gui/SurfaceControl.cpp | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 8 ++- libs/gui/include/gui/SurfaceControl.h | 4 +- 4 files changed, 99 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index cc9e468e16..3f97a969bf 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -322,10 +322,99 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), + mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; + mListenerCallbacks = other.mListenerCallbacks; +} + +std::unique_ptr +SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { + auto transaction = std::make_unique(); + if (transaction->readFromParcel(parcel) == NO_ERROR) { + return transaction; + } + return nullptr; +} + +status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { + const uint32_t forceSynchronous = parcel->readUint32(); + const uint32_t transactionNestCount = parcel->readUint32(); + const bool animation = parcel->readBool(); + const bool earlyWakeup = parcel->readBool(); + const bool containsBuffer = parcel->readBool(); + const int64_t desiredPresentTime = parcel->readInt64(); + + size_t count = static_cast(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + SortedVector displayStates; + displayStates.setCapacity(count); + for (size_t i = 0; i < count; i++) { + DisplayState displayState; + if (displayState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + displayStates.add(displayState); + } + + count = static_cast(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::unordered_map, ComposerState, SCHash> composerStates; + composerStates.reserve(count); + for (size_t i = 0; i < count; i++) { + sp surfaceControl = SurfaceControl::readFromParcel(parcel); + + ComposerState composerState; + if (composerState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + composerStates[surfaceControl] = composerState; + } + + InputWindowCommands inputWindowCommands; + inputWindowCommands.read(*parcel); + + // Parsing was successful. Update the object. + mForceSynchronous = forceSynchronous; + mTransactionNestCount = transactionNestCount; + mAnimation = animation; + mEarlyWakeup = earlyWakeup; + mContainsBuffer = containsBuffer; + mDesiredPresentTime = desiredPresentTime; + mDisplayStates = displayStates; + mComposerStates = composerStates; + mInputWindowCommands = inputWindowCommands; + // listener callbacks contain function pointer addresses and may not be safe to parcel. + mListenerCallbacks.clear(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const { + parcel->writeUint32(mForceSynchronous); + parcel->writeUint32(mTransactionNestCount); + parcel->writeBool(mAnimation); + parcel->writeBool(mEarlyWakeup); + parcel->writeBool(mContainsBuffer); + parcel->writeInt64(mDesiredPresentTime); + parcel->writeUint32(static_cast(mDisplayStates.size())); + for (auto const& displayState : mDisplayStates) { + displayState.write(*parcel); + } + + parcel->writeUint32(static_cast(mComposerStates.size())); + for (auto const& [surfaceControl, composerState] : mComposerStates) { + surfaceControl->writeToParcel(parcel); + composerState.write(*parcel); + } + + mInputWindowCommands.write(*parcel); + return NO_ERROR; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 55488dad0b..d87a447a97 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -186,8 +186,7 @@ void SurfaceControl::writeToParcel(Parcel* parcel) parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); } -sp SurfaceControl::readFromParcel(Parcel* parcel) -{ +sp SurfaceControl::readFromParcel(const Parcel* parcel) { sp client = parcel->readStrongBinder(); sp handle = parcel->readStrongBinder(); if (client == nullptr || handle == nullptr) diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0e17c7b015..1f2947c824 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -285,7 +285,7 @@ public: std::unordered_set, SCHash> surfaceControls; }; - class Transaction { + class Transaction : Parcelable { std::unordered_map, ComposerState, SCHash> mComposerStates; SortedVector mDisplayStates; std::unordered_map, CallbackInfo, TCLHash> @@ -325,6 +325,12 @@ public: virtual ~Transaction() = default; Transaction(Transaction const& other); + // Factory method that creates a new Transaction instance from the parcel. + static std::unique_ptr createFromParcel(const Parcel* parcel); + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + status_t apply(bool synchronous = false); // Merge another transaction in to this one, clearing other // as if it had been applied. diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 23bfc0256b..ae4a14690f 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -44,7 +44,7 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: - static sp readFromParcel(Parcel* parcel); + static sp readFromParcel(const Parcel* parcel); void writeToParcel(Parcel* parcel); static bool isValid(const sp& surface) { @@ -81,7 +81,7 @@ public: status_t getLayerFrameStats(FrameStats* outStats) const; sp getClient() const; - + explicit SurfaceControl(const sp& other); SurfaceControl(const sp& client, const sp& handle, -- cgit v1.2.3-59-g8ed1b From fef244ee2b3ecb326cfa33aaf85efb1490a86ea6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 17 Jun 2019 18:07:51 -0700 Subject: Add SurfaceComposerClient::Transaction clear api When a client parcels a transaction, it is desirable to clear the transaction object since applying the transaction multiple times by different clients may not make sense. Also fixes SurfaceComposerClient::Transaction merge api to clear states like mForceSynchronous when clearing the object. Bug: 132205507 Test: go/wm-smoke Test: test preserve surfaces codepath with split screen and ensure relative z is preserved Change-Id: Iaedb3d420804ff70089817d239273c381b7ebc31 --- libs/gui/SurfaceComposerClient.cpp | 20 ++++++++++++++------ libs/gui/include/gui/SurfaceComposerClient.h | 3 +++ 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3f97a969bf..c59fddfb9d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -425,7 +425,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mComposerStates[kv.first].state.merge(kv.second.state); } } - other.mComposerStates.clear(); for (auto const& state : other.mDisplayStates) { ssize_t index = mDisplayStates.indexOf(state); @@ -435,7 +434,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mDisplayStates.editItemAt(static_cast(index)).merge(state); } } - other.mDisplayStates.clear(); for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; @@ -446,17 +444,27 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()), std::make_move_iterator(surfaceControls.end())); } - other.mListenerCallbacks.clear(); mInputWindowCommands.merge(other.mInputWindowCommands); - other.mInputWindowCommands.clear(); mContainsBuffer = other.mContainsBuffer; - other.mContainsBuffer = false; - + other.clear(); return *this; } +void SurfaceComposerClient::Transaction::clear() { + mComposerStates.clear(); + mDisplayStates.clear(); + mListenerCallbacks.clear(); + mInputWindowCommands.clear(); + mContainsBuffer = false; + mForceSynchronous = 0; + mTransactionNestCount = 0; + mAnimation = false; + mEarlyWakeup = false; + mDesiredPresentTime = -1; +} + void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle, const sp& client) { sp sf(ComposerService::getComposerService()); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 1f2947c824..4dda97f5e1 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -331,6 +331,9 @@ public: status_t writeToParcel(Parcel* parcel) const override; status_t readFromParcel(const Parcel* parcel) override; + // Clears the contents of the transaction without applying it. + void clear(); + status_t apply(bool synchronous = false); // Merge another transaction in to this one, clearing other // as if it had been applied. -- cgit v1.2.3-59-g8ed1b From b2b26909b61efd566db3044d53e258cd5b445166 Mon Sep 17 00:00:00 2001 From: silence_dogood Date: Tue, 18 Jun 2019 14:47:43 -0700 Subject: Revert "Cache NATIVE_WINDOW_MAX_BUFFER_COUNT in Surface" This reverts commit 12536a8fdae818ec39ae274d7da561480f4e1d61. Bug: 135538872 Bug: 133187007 Test: dEQP-VK.wsi.android.surface#query_present_modes --- libs/gui/BufferQueueProducer.cpp | 1 - libs/gui/Surface.cpp | 6 ------ libs/gui/include/gui/IGraphicBufferProducer.h | 1 - libs/gui/include/gui/Surface.h | 1 - 4 files changed, 9 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index b005707fd2..9c311a314f 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1199,7 +1199,6 @@ status_t BufferQueueProducer::connect(const sp& listener, static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; - output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2e8a5d005b..e6eb327c6f 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,7 +96,6 @@ Surface::Surface(const sp& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; - mMaxBufferCount = 0; } Surface::~Surface() { @@ -962,10 +961,6 @@ int Surface::query(int what, int* value) const { *value = static_cast(mDataSpace); return NO_ERROR; } - case NATIVE_WINDOW_MAX_BUFFER_COUNT: { - *value = mMaxBufferCount; - return NO_ERROR; - } } } return mGraphicBufferProducer->query(what, value); @@ -1303,7 +1298,6 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; - mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 6e002dd505..3dde8c8c80 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,7 +412,6 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; - int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 80469dfeaf..0c471bb701 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -465,7 +465,6 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; - int mMaxBufferCount; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From e9d092a9fc53b2b559353c89a58d393a22692c34 Mon Sep 17 00:00:00 2001 From: silence_dogood Date: Wed, 19 Jun 2019 16:14:53 -0700 Subject: Cache NATIVE_WINDOW_MAX_BUFFER_COUNT in Surface To avoid the sync binder call to BufferQueue everytime vkGetPhysicalDeviceSurfaceCapabilitiesKHR and GetPhysicalDeviceSurfacePresentModesKHR are called, we cache the NATIVE_WINDOW_MAX_BUFFER_COUNT at the Surface each time the client connects. Bug: 133187007 Test: dEQP-VK.wsi.android.surface#query_present_modes, libgui_test:BufferQueueTest#GetMaxBufferCountInQueueBufferOutput_Succeeds Change-Id: I7c1a0e99d73151cd451a2f3cb173f843efd57ce1 --- libs/gui/BufferQueueProducer.cpp | 4 +--- libs/gui/IGraphicBufferProducer.cpp | 10 ++++------ libs/gui/Surface.cpp | 6 ++++++ libs/gui/include/gui/IGraphicBufferProducer.h | 1 + libs/gui/include/gui/Surface.h | 1 + libs/gui/tests/BufferQueue_test.cpp | 12 ++++++++++++ 6 files changed, 25 insertions(+), 9 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..b9a4749ccd 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1132,9 +1132,6 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast(mCore->mConsumerIsProtected); break; - case NATIVE_WINDOW_MAX_BUFFER_COUNT: - value = static_cast(mCore->mMaxBufferCount); - break; default: return BAD_VALUE; } @@ -1199,6 +1196,7 @@ status_t BufferQueueProducer::connect(const sp& listener, static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; + output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0e03b7d393..9db0a7ca33 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -1141,12 +1141,8 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( // ---------------------------------------------------------------------------- constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { - return sizeof(width) + - sizeof(height) + - sizeof(transformHint) + - sizeof(numPendingBuffers) + - sizeof(nextFrameNumber) + - sizeof(bufferReplaced); + return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) + + sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount); } size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { @@ -1170,6 +1166,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::flatten( FlattenableUtils::write(buffer, size, numPendingBuffers); FlattenableUtils::write(buffer, size, nextFrameNumber); FlattenableUtils::write(buffer, size, bufferReplaced); + FlattenableUtils::write(buffer, size, maxBufferCount); return frameTimestamps.flatten(buffer, size, fds, count); } @@ -1187,6 +1184,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( FlattenableUtils::read(buffer, size, numPendingBuffers); FlattenableUtils::read(buffer, size, nextFrameNumber); FlattenableUtils::read(buffer, size, bufferReplaced); + FlattenableUtils::read(buffer, size, maxBufferCount); return frameTimestamps.unflatten(buffer, size, fds, count); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..2e8a5d005b 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,6 +96,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; + mMaxBufferCount = 0; } Surface::~Surface() { @@ -961,6 +962,10 @@ int Surface::query(int what, int* value) const { *value = static_cast(mDataSpace); return NO_ERROR; } + case NATIVE_WINDOW_MAX_BUFFER_COUNT: { + *value = mMaxBufferCount; + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -1298,6 +1303,7 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; + mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..6e002dd505 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,6 +412,7 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; + int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..80469dfeaf 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -465,6 +465,7 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; + int mMaxBufferCount; }; } // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 119e888edb..98dc1e6337 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -169,6 +169,18 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) { ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } +TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) { + createBufferQueue(); + sp dc(new DummyConsumer); + mConsumer->consumerConnect(dc, false); + int bufferCount = 50; + mConsumer->setMaxBufferCount(bufferCount); + + IGraphicBufferProducer::QueueBufferOutput output; + mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output); + ASSERT_EQ(output.maxBufferCount, bufferCount); +} + TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { createBufferQueue(); sp dc(new DummyConsumer); -- cgit v1.2.3-59-g8ed1b From cf9bc5fd7558f3806b91b15db6a733f2785c7fa4 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 6 Jun 2019 17:29:18 -0700 Subject: libtimeinstate: fix map names The maps defined by the time_in_state.c BPF program now have names ending with "_map", so update our calls to bpf_obj_get() to reflect that. Test: libtimeinstate_test passes Bug: 78498733 Change-Id: If13df157c0245561eee3efa2a9c5a04f339ca194 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 5fd4a95d7b..4ba66a5066 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -124,7 +124,7 @@ static bool initGlobals() { gPolicyCpus.emplace_back(cpus); } - gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")}; + gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; if (gMapFd < 0) return false; gInitialized = true; @@ -196,7 +196,7 @@ bool getUidsCpuFreqTimes( std::unordered_map>> *freqTimeMap) { if (!gInitialized && !initGlobals()) return false; - int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times"); + int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); if (fd < 0) return false; BpfMap m(fd); -- cgit v1.2.3-59-g8ed1b From 4b9c498812c5f3635c941483a6fec19cb432bcb8 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 5 Jun 2019 18:03:12 -0700 Subject: libtimeinstate: use std::optional Simplify the interface and implementation of libtimeinstate by using std::optional instead of output parameters. Test: libtimeinstate_test passes Bug: 78498733 Change-Id: I97b697c9b51c31245b3c141eff063eba865f5d73 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 65 +++++++++++++++++---------------- libs/cputimeinstate/cputimeinstate.h | 5 ++- libs/cputimeinstate/testtimeinstate.cpp | 37 ++++++++++--------- 3 files changed, 56 insertions(+), 51 deletions(-) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 4ba66a5066..41cbde1c18 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -62,19 +63,20 @@ static std::vector> gPolicyCpus; static std::set gAllFreqs; static unique_fd gMapFd; -static bool readNumbersFromFile(const std::string &path, std::vector *out) { +static std::optional> readNumbersFromFile(const std::string &path) { std::string data; - if (!android::base::ReadFileToString(path, &data)) return false; + if (!android::base::ReadFileToString(path, &data)) return {}; auto strings = android::base::Split(data, " \n"); + std::vector ret; for (const auto &s : strings) { if (s.empty()) continue; uint32_t n; - if (!android::base::ParseUint(s, &n)) return false; - out->emplace_back(n); + if (!android::base::ParseUint(s, &n)) return {}; + ret.emplace_back(n); } - return true; + return ret; } static int isPolicyFile(const struct dirent *d) { @@ -111,17 +113,19 @@ static bool initGlobals() { for (const auto &name : {"available", "boost"}) { std::string path = StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name); - if (!readNumbersFromFile(path, &freqs)) return false; + auto nums = readNumbersFromFile(path); + if (!nums) return false; + freqs.insert(freqs.end(), nums->begin(), nums->end()); } std::sort(freqs.begin(), freqs.end()); gPolicyFreqs.emplace_back(freqs); for (auto freq : freqs) gAllFreqs.insert(freq); - std::vector cpus; std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus"); - if (!readNumbersFromFile(path, &cpus)) return false; - gPolicyCpus.emplace_back(cpus); + auto cpus = readNumbersFromFile(path); + if (!cpus) return false; + gPolicyCpus.emplace_back(*cpus); } gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; @@ -151,17 +155,15 @@ bool startTrackingUidCpuFreqTimes() { } // Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes. -// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors -// using the format: +// Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], // [t1_0, t1_1, ...], ...] // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq. -bool getUidCpuFreqTimes(uint32_t uid, std::vector> *freqTimes) { - if (!gInitialized && !initGlobals()) return false; +std::optional>> getUidCpuFreqTimes(uint32_t uid) { + if (!gInitialized && !initGlobals()) return {}; time_key_t key = {.uid = uid, .freq = 0}; - freqTimes->clear(); - freqTimes->resize(gNPolicies); + std::vector> out(gNPolicies); std::vector idxs(gNPolicies, 0); val_t value; @@ -172,32 +174,32 @@ bool getUidCpuFreqTimes(uint32_t uid, std::vector> *freqTi if (errno == ENOENT) memset(&value.ar, 0, sizeof(value.ar)); else - return false; + return {}; } for (uint32_t i = 0; i < gNPolicies; ++i) { if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue; uint64_t time = 0; for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; idxs[i] += 1; - (*freqTimes)[i].emplace_back(time); + out[i].emplace_back(time); } } - return true; + return out; } // Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap. -// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to -// vectors of vectors using the format: +// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors +// using the format: // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...], // uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... } // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. -bool getUidsCpuFreqTimes( - std::unordered_map>> *freqTimeMap) { - if (!gInitialized && !initGlobals()) return false; +std::optional>>> +getUidsCpuFreqTimes() { + if (!gInitialized && !initGlobals()) return {}; int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); - if (fd < 0) return false; + if (fd < 0) return {}; BpfMap m(fd); std::vector> policyFreqIdxs; @@ -206,25 +208,26 @@ bool getUidsCpuFreqTimes( for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j; policyFreqIdxs.emplace_back(freqIdxs); } - - auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val, + std::unordered_map>> map; + auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val, const BpfMap &) { - if (freqTimeMap->find(key.uid) == freqTimeMap->end()) { - (*freqTimeMap)[key.uid].resize(gNPolicies); + if (map.find(key.uid) == map.end()) { + map[key.uid].resize(gNPolicies); for (uint32_t i = 0; i < gNPolicies; ++i) { - (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0); + map[key.uid][i].resize(gPolicyFreqs[i].size(), 0); } } for (size_t policy = 0; policy < gNPolicies; ++policy) { for (const auto &cpu : gPolicyCpus[policy]) { auto freqIdx = policyFreqIdxs[policy][key.freq]; - (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu]; + map[key.uid][policy][freqIdx] += val.ar[cpu]; } } return android::netdutils::status::ok; }; - return isOk(m.iterateWithValue(fn)); + if (isOk(m.iterateWithValue(fn))) return map; + return {}; } // Clear all time in state data for a given uid. Returns false on error, true otherwise. diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index 9f6103ed9b..d7b45870ac 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -23,8 +23,9 @@ namespace android { namespace bpf { bool startTrackingUidCpuFreqTimes(); -bool getUidCpuFreqTimes(unsigned int uid, std::vector> *freqTimes); -bool getUidsCpuFreqTimes(std::unordered_map>> *tisMap); +std::optional>> getUidCpuFreqTimes(uint32_t uid); +std::optional>>> + getUidsCpuFreqTimes(); bool clearUidCpuFreqTimes(unsigned int uid); } // namespace bpf diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 9837865dfb..d4b87386e0 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -12,45 +12,46 @@ namespace bpf { using std::vector; TEST(TimeInStateTest, SingleUid) { - vector> times; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - EXPECT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + EXPECT_FALSE(times->empty()); } TEST(TimeInStateTest, AllUid) { vector sizes; - std::unordered_map>> map; - ASSERT_TRUE(getUidsCpuFreqTimes(&map)); + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map.empty()); + ASSERT_FALSE(map->empty()); - auto firstEntry = map.begin()->second; + auto firstEntry = map->begin()->second; for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); - for (const auto &vec : map) { + for (const auto &vec : *map) { ASSERT_EQ(vec.second.size(), sizes.size()); for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); } } TEST(TimeInStateTest, RemoveUid) { - vector> times, times2; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - ASSERT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); uint64_t sum = 0; - for (size_t i = 0; i < times.size(); ++i) { - for (auto x : times[i]) sum += x; + for (size_t i = 0; i < times->size(); ++i) { + for (auto x : (*times)[i]) sum += x; } ASSERT_GT(sum, (uint64_t)0); ASSERT_TRUE(clearUidCpuFreqTimes(0)); - ASSERT_TRUE(getUidCpuFreqTimes(0, ×2)); - ASSERT_EQ(times2.size(), times.size()); - for (size_t i = 0; i < times.size(); ++i) { - ASSERT_EQ(times2[i].size(), times[i].size()); - for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]); + auto times2 = getUidCpuFreqTimes(0); + ASSERT_TRUE(times2.has_value()); + ASSERT_EQ(times2->size(), times->size()); + for (size_t i = 0; i < times->size(); ++i) { + ASSERT_EQ((*times2)[i].size(), (*times)[i].size()); + for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]); } } -- cgit v1.2.3-59-g8ed1b From 3e092daa14c63831d76d3ad6e56b2919a0523536 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 21 Jun 2019 12:35:59 -0700 Subject: servicemanager: use libbinder Bug: 135768100 Test: boot Test: servicemanager_test Change-Id: I9d657b6c0d0be0f763b6d54e0e6c6bc1c1e3fc7a --- cmds/servicemanager/Access.cpp | 140 +++++ cmds/servicemanager/Access.h | 59 ++ cmds/servicemanager/Android.bp | 54 +- cmds/servicemanager/ServiceManager.cpp | 144 +++++ cmds/servicemanager/ServiceManager.h | 47 ++ cmds/servicemanager/TEST_MAPPING | 7 + cmds/servicemanager/bctest.c | 107 ---- cmds/servicemanager/binder.c | 682 ----------------------- cmds/servicemanager/binder.h | 94 ---- cmds/servicemanager/main.cpp | 54 ++ cmds/servicemanager/service_manager.c | 442 --------------- cmds/servicemanager/test_sm.cpp | 261 +++++++++ libs/binder/Android.bp | 4 +- libs/binder/IPCThreadState.cpp | 2 +- libs/binder/IServiceManager.cpp | 58 +- libs/binder/aidl/android/os/IServiceManager.aidl | 80 +++ libs/binder/include/binder/IPCThreadState.h | 2 + 17 files changed, 851 insertions(+), 1386 deletions(-) create mode 100644 cmds/servicemanager/Access.cpp create mode 100644 cmds/servicemanager/Access.h create mode 100644 cmds/servicemanager/ServiceManager.cpp create mode 100644 cmds/servicemanager/ServiceManager.h create mode 100644 cmds/servicemanager/TEST_MAPPING delete mode 100644 cmds/servicemanager/bctest.c delete mode 100644 cmds/servicemanager/binder.c delete mode 100644 cmds/servicemanager/binder.h create mode 100644 cmds/servicemanager/main.cpp delete mode 100644 cmds/servicemanager/service_manager.c create mode 100644 cmds/servicemanager/test_sm.cpp create mode 100644 libs/binder/aidl/android/os/IServiceManager.aidl (limited to 'libs') diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp new file mode 100644 index 0000000000..f4005c4dee --- /dev/null +++ b/cmds/servicemanager/Access.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 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 "Access.h" + +#include +#include +#include +#include +#include + +namespace android { + +#ifdef VENDORSERVICEMANAGER +constexpr bool kIsVendor = true; +#else +constexpr bool kIsVendor = false; +#endif + +static std::string getPidcon(pid_t pid) { + android_errorWriteLog(0x534e4554, "121035042"); + + char* lookup = nullptr; + if (getpidcon(pid, &lookup) < 0) { + LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context"; + return ""; + } + std::string result = lookup; + freecon(lookup); + return result; +} + +static struct selabel_handle* getSehandle() { + static struct selabel_handle* gSehandle = nullptr; + + if (gSehandle != nullptr && selinux_status_updated()) { + selabel_close(gSehandle); + gSehandle = nullptr; + } + + if (gSehandle == nullptr) { + gSehandle = kIsVendor + ? selinux_android_vendor_service_context_handle() + : selinux_android_service_context_handle(); + } + + CHECK(gSehandle != nullptr); + return gSehandle; +} + +static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) { + const Access::CallingContext* ad = reinterpret_cast(data); + + if (!ad) { + LOG(ERROR) << "No service manager audit data"; + return 0; + } + + snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name.c_str(), ad->debugPid, ad->uid); + return 0; +} + +Access::Access() { + union selinux_callback cb; + + cb.func_audit = auditCallback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); + + cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); + + CHECK(selinux_status_open(true /*fallback*/) >= 0); + + CHECK(getcon(&mThisProcessContext) == 0); +} + +Access::~Access() { + freecon(mThisProcessContext); +} + +Access::CallingContext Access::getCallingContext(const std::string& name) { + IPCThreadState* ipc = IPCThreadState::self(); + + const char* callingSid = ipc->getCallingSid(); + pid_t callingPid = ipc->getCallingPid(); + + return CallingContext { + .debugPid = callingPid, + .uid = ipc->getCallingUid(), + .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), + .name = name, + }; +} + +bool Access::canFind(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "find"); +} + +bool Access::canAdd(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "add"); +} + +bool Access::canList(const CallingContext& ctx) { + CHECK(ctx.name == ""); + + return actionAllowed(ctx, mThisProcessContext, "list"); +} + +bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) { + const char* tclass = "service_manager"; + + return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast(const_cast((&sctx)))); +} + +bool Access::actionAllowedFromLookup(const CallingContext& sctx, const char *perm) { + char *tctx = nullptr; + if (selabel_lookup(getSehandle(), &tctx, sctx.name.c_str(), 0) != 0) { + LOG(ERROR) << "SELinux: No match for " << sctx.name << " in service_contexts.\n"; + return false; + } + + bool allowed = actionAllowed(sctx, tctx, perm); + freecon(tctx); + return allowed; +} + +} // android diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h new file mode 100644 index 0000000000..b2c78cc34d --- /dev/null +++ b/cmds/servicemanager/Access.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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 +#include + +namespace android { + +// singleton +class Access { +public: + Access(); + virtual ~Access(); + + Access(const Access&) = delete; + Access& operator=(const Access&) = delete; + Access(Access&&) = delete; + Access& operator=(Access&&) = delete; + + struct CallingContext { + pid_t debugPid; + uid_t uid; + std::string sid; + + // name of the service + // + // empty if call is unrelated to service (e.g. list) + std::string name; + }; + + virtual CallingContext getCallingContext(const std::string& name); + + virtual bool canFind(const CallingContext& ctx); + virtual bool canAdd(const CallingContext& ctx); + virtual bool canList(const CallingContext& ctx); + +private: + bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm); + bool actionAllowedFromLookup(const CallingContext& sctx, const char *perm); + + char* mThisProcessContext = nullptr; +}; + +}; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 428561bc8a..9cf3c5c134 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -1,51 +1,51 @@ cc_defaults { - name: "servicemanager_flags", + name: "servicemanager_defaults", cflags: [ "-Wall", "-Wextra", "-Werror", ], - product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - }, - shared_libs: ["liblog"], -} - -cc_binary { - name: "bctest", - defaults: ["servicemanager_flags"], srcs: [ - "bctest.c", - "binder.c", + "Access.cpp", + "ServiceManager.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder", // also contains servicemanager_interface + "libcutils", + "liblog", + "libutils", + "libselinux", ], } cc_binary { name: "servicemanager", - defaults: ["servicemanager_flags"], - srcs: [ - "service_manager.c", - "binder.c", - ], - shared_libs: ["libcutils", "libselinux"], + defaults: ["servicemanager_defaults"], init_rc: ["servicemanager.rc"], + srcs: ["main.cpp"], } cc_binary { name: "vndservicemanager", - defaults: ["servicemanager_flags"], + defaults: ["servicemanager_defaults"], + init_rc: ["vndservicemanager.rc"], vendor: true, - srcs: [ - "service_manager.c", - "binder.c", - ], cflags: [ "-DVENDORSERVICEMANAGER=1", ], - shared_libs: ["libcutils", "libselinux"], - init_rc: ["vndservicemanager.rc"], + srcs: ["main.cpp"], +} + +cc_test { + name: "servicemanager_test", + test_suites: ["device-tests"], + defaults: ["servicemanager_defaults"], + srcs: [ + "test_sm.cpp", + ], + static_libs: ["libgmock"], } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp new file mode 100644 index 0000000000..b88b67d138 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2019 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 "ServiceManager.h" + +#include +#include +#include + +using ::android::binder::Status; + +namespace android { + +ServiceManager::ServiceManager(std::unique_ptr&& access) : mAccess(std::move(access)) {} + +Status ServiceManager::getService(const std::string& name, sp* outBinder) { + // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. + return checkService(name, outBinder); +} + +Status ServiceManager::checkService(const std::string& name, sp* outBinder) { + auto ctx = mAccess->getCallingContext(name); + + auto it = mNameToService.find(name); + if (it == mNameToService.end()) { + *outBinder = nullptr; + return Status::ok(); + } + + const Service& service = it->second; + + if (!service.allowIsolated) { + uid_t appid = multiuser_get_app_id(ctx.uid); + bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; + + if (isIsolated) { + *outBinder = nullptr; + return Status::ok(); + } + } + + // TODO(b/136023468): move this check to be first + if (!mAccess->canFind(ctx)) { + // returns ok and null for legacy reasons + *outBinder = nullptr; + return Status::ok(); + } + + *outBinder = service.binder; + return Status::ok(); +} + +Status ServiceManager::addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) { + auto ctx = mAccess->getCallingContext(name); + + // apps cannot add services + if (multiuser_get_app_id(ctx.uid) >= AID_APP) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (!mAccess->canAdd(ctx)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (binder == nullptr) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + // match legacy rules + if (name.size() == 0 || name.size() > 127) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if (OK != binder->linkToDeath(this)) { + LOG(ERROR) << "Could not linkToDeath when adding " << name; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + auto it = mNameToService.find(name); + if (it != mNameToService.end()) { + if (OK != it->second.binder->unlinkToDeath(this)) { + LOG(WARNING) << "Could not unlinkToDeath when adding " << name; + } + } + + mNameToService[name] = Service { + .binder = binder, + .allowIsolated = allowIsolated, + .dumpPriority = dumpPriority, + }; + + return Status::ok(); +} + +Status ServiceManager::listServices(int32_t dumpPriority, std::vector* outList) { + if (!mAccess->canList(mAccess->getCallingContext(""))) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + size_t toReserve = 0; + for (auto const& [name, service] : mNameToService) { + (void) name; + + if (service.dumpPriority & dumpPriority) ++toReserve; + } + + CHECK(outList->empty()); + + outList->reserve(toReserve); + for (auto const& [name, service] : mNameToService) { + (void) service; + + if (service.dumpPriority & dumpPriority) { + outList->push_back(name); + } + } + + return Status::ok(); +} + +void ServiceManager::binderDied(const wp& who) { + for (auto it = mNameToService.begin(); it != mNameToService.end();) { + if (who == it->second.binder) { + it = mNameToService.erase(it); + } else { + ++it; + } + } +} + +} // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h new file mode 100644 index 0000000000..78e48052b8 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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 + +#include "Access.h" + +namespace android { + +class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { +public: + ServiceManager(std::unique_ptr&& access); + + binder::Status getService(const std::string& name, sp* outBinder) override; + binder::Status checkService(const std::string& name, sp* outBinder) override; + binder::Status addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) override; + binder::Status listServices(int32_t dumpPriority, std::vector* outList) override; + + void binderDied(const wp& who) override; + +private: + struct Service { + sp binder; + bool allowIsolated; + int32_t dumpPriority; + }; + + std::map mNameToService; + std::unique_ptr mAccess; +}; + +} // namespace android diff --git a/cmds/servicemanager/TEST_MAPPING b/cmds/servicemanager/TEST_MAPPING new file mode 100644 index 0000000000..3e47269fe0 --- /dev/null +++ b/cmds/servicemanager/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "servicemanager_test" + } + ] +} diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c deleted file mode 100644 index 354df670e5..0000000000 --- a/cmds/servicemanager/bctest.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include -#include -#include -#include - -#include "binder.h" - -uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) -{ - uint32_t handle; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) - return 0; - - handle = bio_get_ref(&reply); - - if (handle) - binder_acquire(bs, handle); - - binder_done(bs, &msg, &reply); - - return handle; -} - -int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) -{ - int status; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - bio_put_obj(&msg, ptr); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) - return -1; - - status = bio_get_uint32(&reply); - - binder_done(bs, &msg, &reply); - - return status; -} - -unsigned token; - -int main(int argc, char **argv) -{ - struct binder_state *bs; - uint32_t svcmgr = BINDER_SERVICE_MANAGER; - uint32_t handle; - - bs = binder_open("/dev/binder", 128*1024); - if (!bs) { - fprintf(stderr, "failed to open binder driver\n"); - return -1; - } - - argc--; - argv++; - while (argc > 0) { - if (!strcmp(argv[0],"alt")) { - handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); - if (!handle) { - fprintf(stderr,"cannot find alt_svc_mgr\n"); - return -1; - } - svcmgr = handle; - fprintf(stderr,"svcmgr is via %x\n", handle); - } else if (!strcmp(argv[0],"lookup")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - handle = svcmgr_lookup(bs, svcmgr, argv[1]); - fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); - argc--; - argv++; - } else if (!strcmp(argv[0],"publish")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - svcmgr_publish(bs, svcmgr, argv[1], &token); - argc--; - argv++; - } else { - fprintf(stderr,"unknown command %s\n", argv[0]); - return -1; - } - argc--; - argv++; - } - return 0; -} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c deleted file mode 100644 index cf3b1728b6..0000000000 --- a/cmds/servicemanager/binder.c +++ /dev/null @@ -1,682 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#define LOG_TAG "Binder" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "binder.h" - -#define MAX_BIO_SIZE (1 << 30) - -#define TRACE 0 - -void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn); - -#if TRACE -void hexdump(void *_data, size_t len) -{ - unsigned char *data = _data; - size_t count; - - for (count = 0; count < len; count++) { - if ((count & 15) == 0) - fprintf(stderr,"%04zu:", count); - fprintf(stderr," %02x %c", *data, - (*data < 32) || (*data > 126) ? '.' : *data); - data++; - if ((count & 15) == 15) - fprintf(stderr,"\n"); - } - if ((count & 15) != 0) - fprintf(stderr,"\n"); -} - -void binder_dump_txn(struct binder_transaction_data *txn) -{ - struct flat_binder_object *obj; - binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets; - size_t count = txn->offsets_size / sizeof(binder_size_t); - - fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n", - (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags); - fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n", - txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size); - hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size); - while (count--) { - obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++); - fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n", - obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie); - } -} - -#define NAME(n) case n: return #n -const char *cmd_name(uint32_t cmd) -{ - switch(cmd) { - NAME(BR_NOOP); - NAME(BR_TRANSACTION_COMPLETE); - NAME(BR_INCREFS); - NAME(BR_ACQUIRE); - NAME(BR_RELEASE); - NAME(BR_DECREFS); - NAME(BR_TRANSACTION); - NAME(BR_REPLY); - NAME(BR_FAILED_REPLY); - NAME(BR_DEAD_REPLY); - NAME(BR_DEAD_BINDER); - default: return "???"; - } -} -#else -#define hexdump(a,b) do{} while (0) -#define binder_dump_txn(txn) do{} while (0) -#endif - -#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ -#define BIO_F_OVERFLOW 0x02 /* ran out of space */ -#define BIO_F_IOERROR 0x04 -#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ - -struct binder_state -{ - int fd; - void *mapped; - size_t mapsize; -}; - -struct binder_state *binder_open(const char* driver, size_t mapsize) -{ - struct binder_state *bs; - struct binder_version vers; - - bs = malloc(sizeof(*bs)); - if (!bs) { - errno = ENOMEM; - return NULL; - } - - bs->fd = open(driver, O_RDWR | O_CLOEXEC); - if (bs->fd < 0) { - fprintf(stderr,"binder: cannot open %s (%s)\n", - driver, strerror(errno)); - goto fail_open; - } - - if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || - (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { - fprintf(stderr, - "binder: kernel driver version (%d) differs from user space version (%d)\n", - vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); - goto fail_open; - } - - bs->mapsize = mapsize; - bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); - if (bs->mapped == MAP_FAILED) { - fprintf(stderr,"binder: cannot map device (%s)\n", - strerror(errno)); - goto fail_map; - } - - return bs; - -fail_map: - close(bs->fd); -fail_open: - free(bs); - return NULL; -} - -void binder_close(struct binder_state *bs) -{ - munmap(bs->mapped, bs->mapsize); - close(bs->fd); - free(bs); -} - -int binder_become_context_manager(struct binder_state *bs) -{ - struct flat_binder_object obj; - memset(&obj, 0, sizeof(obj)); - obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; - - int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj); - - // fallback to original method - if (result != 0) { - android_errorWriteLog(0x534e4554, "121035042"); - - result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); - } - return result; -} - -int binder_write(struct binder_state *bs, void *data, size_t len) -{ - struct binder_write_read bwr; - int res; - - bwr.write_size = len; - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) data; - bwr.read_size = 0; - bwr.read_consumed = 0; - bwr.read_buffer = 0; - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - if (res < 0) { - fprintf(stderr,"binder_write: ioctl failed (%s)\n", - strerror(errno)); - } - return res; -} - -void binder_free_buffer(struct binder_state *bs, - binder_uintptr_t buffer_to_free) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - } __attribute__((packed)) data; - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - binder_write(bs, &data, sizeof(data)); -} - -void binder_send_reply(struct binder_state *bs, - struct binder_io *reply, - binder_uintptr_t buffer_to_free, - int status) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - uint32_t cmd_reply; - struct binder_transaction_data txn; - } __attribute__((packed)) data; - - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - data.cmd_reply = BC_REPLY; - data.txn.target.ptr = 0; - data.txn.cookie = 0; - data.txn.code = 0; - if (status) { - data.txn.flags = TF_STATUS_CODE; - data.txn.data_size = sizeof(int); - data.txn.offsets_size = 0; - data.txn.data.ptr.buffer = (uintptr_t)&status; - data.txn.data.ptr.offsets = 0; - } else { - data.txn.flags = 0; - data.txn.data_size = reply->data - reply->data0; - data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); - data.txn.data.ptr.buffer = (uintptr_t)reply->data0; - data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; - } - binder_write(bs, &data, sizeof(data)); -} - -int binder_parse(struct binder_state *bs, struct binder_io *bio, - uintptr_t ptr, size_t size, binder_handler func) -{ - int r = 1; - uintptr_t end = ptr + (uintptr_t) size; - - while (ptr < end) { - uint32_t cmd = *(uint32_t *) ptr; - ptr += sizeof(uint32_t); -#if TRACE - fprintf(stderr,"%s:\n", cmd_name(cmd)); -#endif - switch(cmd) { - case BR_NOOP: - break; - case BR_TRANSACTION_COMPLETE: - break; - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: -#if TRACE - fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *))); -#endif - ptr += sizeof(struct binder_ptr_cookie); - break; - case BR_TRANSACTION_SEC_CTX: - case BR_TRANSACTION: { - struct binder_transaction_data_secctx txn; - if (cmd == BR_TRANSACTION_SEC_CTX) { - if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) { - ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n"); - return -1; - } - memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx)); - ptr += sizeof(struct binder_transaction_data_secctx); - } else /* BR_TRANSACTION */ { - if ((end - ptr) < sizeof(struct binder_transaction_data)) { - ALOGE("parse: txn too small (binder_transaction_data)!\n"); - return -1; - } - memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data)); - ptr += sizeof(struct binder_transaction_data); - - txn.secctx = 0; - } - - binder_dump_txn(&txn.transaction_data); - if (func) { - unsigned rdata[256/4]; - struct binder_io msg; - struct binder_io reply; - int res; - - bio_init(&reply, rdata, sizeof(rdata), 4); - bio_init_from_txn(&msg, &txn.transaction_data); - res = func(bs, &txn, &msg, &reply); - if (txn.transaction_data.flags & TF_ONE_WAY) { - binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer); - } else { - binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res); - } - } - break; - } - case BR_REPLY: { - struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; - if ((end - ptr) < sizeof(*txn)) { - ALOGE("parse: reply too small!\n"); - return -1; - } - binder_dump_txn(txn); - if (bio) { - bio_init_from_txn(bio, txn); - bio = 0; - } else { - /* todo FREE BUFFER */ - } - ptr += sizeof(*txn); - r = 0; - break; - } - case BR_DEAD_BINDER: { - struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr; - ptr += sizeof(binder_uintptr_t); - death->func(bs, death->ptr); - break; - } - case BR_FAILED_REPLY: - r = -1; - break; - case BR_DEAD_REPLY: - r = -1; - break; - default: - ALOGE("parse: OOPS %d\n", cmd); - return -1; - } - } - - return r; -} - -void binder_acquire(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_ACQUIRE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_release(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_RELEASE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death) -{ - struct { - uint32_t cmd; - struct binder_handle_cookie payload; - } __attribute__((packed)) data; - - data.cmd = BC_REQUEST_DEATH_NOTIFICATION; - data.payload.handle = target; - data.payload.cookie = (uintptr_t) death; - binder_write(bs, &data, sizeof(data)); -} - -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code) -{ - int res; - struct binder_write_read bwr; - struct { - uint32_t cmd; - struct binder_transaction_data txn; - } __attribute__((packed)) writebuf; - unsigned readbuf[32]; - - if (msg->flags & BIO_F_OVERFLOW) { - fprintf(stderr,"binder: txn buffer overflow\n"); - goto fail; - } - - writebuf.cmd = BC_TRANSACTION; - writebuf.txn.target.handle = target; - writebuf.txn.code = code; - writebuf.txn.flags = 0; - writebuf.txn.data_size = msg->data - msg->data0; - writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); - writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; - writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; - - bwr.write_size = sizeof(writebuf); - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) &writebuf; - - hexdump(msg->data0, msg->data - msg->data0); - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); - goto fail; - } - - res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); - if (res == 0) return 0; - if (res < 0) goto fail; - } - -fail: - memset(reply, 0, sizeof(*reply)); - reply->flags |= BIO_F_IOERROR; - return -1; -} - -void binder_loop(struct binder_state *bs, binder_handler func) -{ - int res; - struct binder_write_read bwr; - uint32_t readbuf[32]; - - bwr.write_size = 0; - bwr.write_consumed = 0; - bwr.write_buffer = 0; - - readbuf[0] = BC_ENTER_LOOPER; - binder_write(bs, readbuf, sizeof(uint32_t)); - - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); - break; - } - - res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); - if (res == 0) { - ALOGE("binder_loop: unexpected reply?!\n"); - break; - } - if (res < 0) { - ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); - break; - } - } -} - -void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn) -{ - bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer; - bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets; - bio->data_avail = txn->data_size; - bio->offs_avail = txn->offsets_size / sizeof(size_t); - bio->flags = BIO_F_SHARED; -} - -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxoffs) -{ - size_t n = maxoffs * sizeof(size_t); - - if (n > maxdata) { - bio->flags = BIO_F_OVERFLOW; - bio->data_avail = 0; - bio->offs_avail = 0; - return; - } - - bio->data = bio->data0 = (char *) data + n; - bio->offs = bio->offs0 = data; - bio->data_avail = maxdata - n; - bio->offs_avail = maxoffs; - bio->flags = 0; -} - -static void *bio_alloc(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - if (size > bio->data_avail) { - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -void binder_done(struct binder_state *bs, - __unused struct binder_io *msg, - struct binder_io *reply) -{ - struct { - uint32_t cmd; - uintptr_t buffer; - } __attribute__((packed)) data; - - if (reply->flags & BIO_F_SHARED) { - data.cmd = BC_FREE_BUFFER; - data.buffer = (uintptr_t) reply->data0; - binder_write(bs, &data, sizeof(data)); - reply->flags = 0; - } -} - -static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = bio_alloc(bio, sizeof(*obj)); - - if (obj && bio->offs_avail) { - bio->offs_avail--; - *bio->offs++ = ((char*) obj) - ((char*) bio->data0); - return obj; - } - - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -void bio_put_uint32(struct binder_io *bio, uint32_t n) -{ - uint32_t *ptr = bio_alloc(bio, sizeof(n)); - if (ptr) - *ptr = n; -} - -void bio_put_obj(struct binder_io *bio, void *ptr) -{ - struct flat_binder_object *obj; - - obj = bio_alloc_obj(bio); - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_BINDER; - obj->binder = (uintptr_t)ptr; - obj->cookie = 0; -} - -void bio_put_ref(struct binder_io *bio, uint32_t handle) -{ - struct flat_binder_object *obj; - - if (handle) - obj = bio_alloc_obj(bio); - else - obj = bio_alloc(bio, sizeof(*obj)); - - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_HANDLE; - obj->handle = handle; - obj->cookie = 0; -} - -void bio_put_string16(struct binder_io *bio, const uint16_t *str) -{ - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = 0; - while (str[len]) len++; - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, (uint32_t) len); - len = (len + 1) * sizeof(uint16_t); - ptr = bio_alloc(bio, len); - if (ptr) - memcpy(ptr, str, len); -} - -void bio_put_string16_x(struct binder_io *bio, const char *_str) -{ - unsigned char *str = (unsigned char*) _str; - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = strlen(_str); - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, len); - ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); - if (!ptr) - return; - - while (*str) - *ptr++ = *str++; - *ptr++ = 0; -} - -static void *bio_get(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - - if (bio->data_avail < size){ - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -uint32_t bio_get_uint32(struct binder_io *bio) -{ - uint32_t *ptr = bio_get(bio, sizeof(*ptr)); - return ptr ? *ptr : 0; -} - -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz) -{ - size_t len; - - /* Note: The payload will carry 32bit size instead of size_t */ - len = (size_t) bio_get_uint32(bio); - if (sz) - *sz = len; - return bio_get(bio, (len + 1) * sizeof(uint16_t)); -} - -static struct flat_binder_object *_bio_get_obj(struct binder_io *bio) -{ - size_t n; - size_t off = bio->data - bio->data0; - - /* TODO: be smarter about this? */ - for (n = 0; n < bio->offs_avail; n++) { - if (bio->offs[n] == off) - return bio_get(bio, sizeof(struct flat_binder_object)); - } - - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -uint32_t bio_get_ref(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = _bio_get_obj(bio); - if (!obj) - return 0; - - if (obj->hdr.type == BINDER_TYPE_HANDLE) - return obj->handle; - - return 0; -} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h deleted file mode 100644 index a9ccc74130..0000000000 --- a/cmds/servicemanager/binder.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#ifndef _BINDER_H_ -#define _BINDER_H_ - -#include -#include - -struct binder_state; - -struct binder_io -{ - char *data; /* pointer to read/write from */ - binder_size_t *offs; /* array of offsets */ - size_t data_avail; /* bytes available in data buffer */ - size_t offs_avail; /* entries available in offsets array */ - - char *data0; /* start of data buffer */ - binder_size_t *offs0; /* start of offsets buffer */ - uint32_t flags; - uint32_t unused; -}; - -struct binder_death { - void (*func)(struct binder_state *bs, void *ptr); - void *ptr; -}; - -/* the one magic handle */ -#define BINDER_SERVICE_MANAGER 0U - -#define SVC_MGR_NAME "android.os.IServiceManager" - -enum { - /* Must match definitions in IBinder.h and IServiceManager.h */ - PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), - SVC_MGR_GET_SERVICE = 1, - SVC_MGR_CHECK_SERVICE, - SVC_MGR_ADD_SERVICE, - SVC_MGR_LIST_SERVICES, -}; - -typedef int (*binder_handler)(struct binder_state *bs, - struct binder_transaction_data_secctx *txn, - struct binder_io *msg, - struct binder_io *reply); - -struct binder_state *binder_open(const char* driver, size_t mapsize); -void binder_close(struct binder_state *bs); - -/* initiate a blocking binder call - * - returns zero on success - */ -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code); - -/* release any state associate with the binder_io - * - call once any necessary data has been extracted from the - * binder_io after binder_call() returns - * - can safely be called even if binder_call() fails - */ -void binder_done(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply); - -/* manipulate strong references */ -void binder_acquire(struct binder_state *bs, uint32_t target); -void binder_release(struct binder_state *bs, uint32_t target); - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); - -void binder_loop(struct binder_state *bs, binder_handler func); - -int binder_become_context_manager(struct binder_state *bs); - -/* allocate a binder_io, providing a stack-allocated working - * buffer, size of the working buffer, and how many object - * offset entries to reserve from the buffer - */ -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxobjects); - -void bio_put_obj(struct binder_io *bio, void *ptr); -void bio_put_ref(struct binder_io *bio, uint32_t handle); -void bio_put_uint32(struct binder_io *bio, uint32_t n); -void bio_put_string16(struct binder_io *bio, const uint16_t *str); -void bio_put_string16_x(struct binder_io *bio, const char *_str); - -uint32_t bio_get_uint32(struct binder_io *bio); -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); -uint32_t bio_get_ref(struct binder_io *bio); - -#endif diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp new file mode 100644 index 0000000000..c8ceb42ac8 --- /dev/null +++ b/cmds/servicemanager/main.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 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 +#include +#include +#include +#include + +#include "Access.h" +#include "ServiceManager.h" + +using ::android::sp; +using ::android::ProcessState; +using ::android::IPCThreadState; +using ::android::ServiceManager; +using ::android::Access; + +int main(int argc, char** argv) { + if (argc > 2) { + LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; + } + + const char* driver = argc == 2 ? argv[1] : "/dev/binder"; + + android::base::InitLogging(nullptr, &android::base::KernelLogger); + + ProcessState::self()->initWithDriver(driver); + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->setCallRestriction( + ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); + + sp manager = new ServiceManager(std::make_unique()); + IPCThreadState::self()->setTheContextObject(manager); + ProcessState::self()->becomeContextManager(nullptr, nullptr); + + IPCThreadState::self()->joinThreadPool(); + + // should not be reached + return EXIT_FAILURE; +} diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c deleted file mode 100644 index ec3fac538d..0000000000 --- a/cmds/servicemanager/service_manager.c +++ /dev/null @@ -1,442 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "binder.h" - -#ifdef VENDORSERVICEMANAGER -#define LOG_TAG "VendorServiceManager" -#else -#define LOG_TAG "ServiceManager" -#endif -#include - -struct audit_data { - pid_t pid; - uid_t uid; - const char *name; -}; - -const char *str8(const uint16_t *x, size_t x_len) -{ - static char buf[128]; - size_t max = 127; - char *p = buf; - - if (x_len < max) { - max = x_len; - } - - if (x) { - while ((max > 0) && (*x != '\0')) { - *p++ = *x++; - max--; - } - } - *p++ = 0; - return buf; -} - -int str16eq(const uint16_t *a, const char *b) -{ - while (*a && *b) - if (*a++ != *b++) return 0; - if (*a || *b) - return 0; - return 1; -} - -static char *service_manager_context; -static struct selabel_handle* sehandle; - -static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name) -{ - char *lookup_sid = NULL; - const char *class = "service_manager"; - bool allowed; - struct audit_data ad; - - if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) { - ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); - return false; - } - - ad.pid = spid; - ad.uid = uid; - ad.name = name; - - if (sid == NULL) { - android_errorWriteLog(0x534e4554, "121035042"); - } - - int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad); - allowed = (result == 0); - - freecon(lookup_sid); - return allowed; -} - -static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm) -{ - return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL); -} - -static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name) -{ - bool allowed; - char *tctx = NULL; - - if (!sehandle) { - ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); - abort(); - } - - if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { - ALOGE("SELinux: No match for %s in service_contexts.\n", name); - return false; - } - - allowed = check_mac_perms(spid, sid, uid, tctx, perm, name); - freecon(tctx); - return allowed; -} - -static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "add"; - - if (multiuser_get_app_id(uid) >= AID_APP) { - return 0; /* Don't allow apps to register services */ - } - - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -static int svc_can_list(pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "list"; - return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0; -} - -static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "find"; - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -struct svcinfo -{ - struct svcinfo *next; - uint32_t handle; - struct binder_death death; - int allow_isolated; - uint32_t dumpsys_priority; - size_t len; - uint16_t name[0]; -}; - -struct svcinfo *svclist = NULL; - -struct svcinfo *find_svc(const uint16_t *s16, size_t len) -{ - struct svcinfo *si; - - for (si = svclist; si; si = si->next) { - if ((len == si->len) && - !memcmp(s16, si->name, len * sizeof(uint16_t))) { - return si; - } - } - return NULL; -} - -void svcinfo_death(struct binder_state *bs, void *ptr) -{ - struct svcinfo *si = (struct svcinfo* ) ptr; - - ALOGI("service '%s' died\n", str8(si->name, si->len)); - if (si->handle) { - binder_release(bs, si->handle); - si->handle = 0; - } -} - -uint16_t svcmgr_id[] = { - 'a','n','d','r','o','i','d','.','o','s','.', - 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' -}; - - -uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) -{ - struct svcinfo *si = find_svc(s, len); - - if (!si || !si->handle) { - return 0; - } - - if (!si->allow_isolated) { - // If this service doesn't allow access from isolated processes, - // then check the uid to see if it is isolated. - uid_t appid = uid % AID_USER; - if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { - return 0; - } - } - - if (!svc_can_find(s, len, spid, sid, uid)) { - return 0; - } - - return si->handle; -} - -int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, - uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) { - struct svcinfo *si; - - //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, - // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); - - if (!handle || (len == 0) || (len > 127)) - return -1; - - if (!svc_can_register(s, len, spid, sid, uid)) { - ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", - str8(s, len), handle, uid); - return -1; - } - - si = find_svc(s, len); - if (si) { - if (si->handle) { - ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", - str8(s, len), handle, uid); - svcinfo_death(bs, si); - } - si->handle = handle; - } else { - si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); - if (!si) { - ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", - str8(s, len), handle, uid); - return -1; - } - si->handle = handle; - si->len = len; - memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); - si->name[len] = '\0'; - si->death.func = (void*) svcinfo_death; - si->death.ptr = si; - si->allow_isolated = allow_isolated; - si->dumpsys_priority = dumpsys_priority; - si->next = svclist; - svclist = si; - } - - binder_acquire(bs, handle); - binder_link_to_death(bs, handle, &si->death); - return 0; -} - -int svcmgr_handler(struct binder_state *bs, - struct binder_transaction_data_secctx *txn_secctx, - struct binder_io *msg, - struct binder_io *reply) -{ - struct svcinfo *si; - uint16_t *s; - size_t len; - uint32_t handle; - uint32_t strict_policy; - int allow_isolated; - uint32_t dumpsys_priority; - - struct binder_transaction_data *txn = &txn_secctx->transaction_data; - - //ALOGI("target=%p code=%d pid=%d uid=%d\n", - // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); - - if (txn->target.ptr != BINDER_SERVICE_MANAGER) - return -1; - - if (txn->code == PING_TRANSACTION) - return 0; - - // Equivalent to Parcel::enforceInterface(), reading the RPC - // header with the strict mode policy mask and the interface name. - // Note that we ignore the strict_policy and don't propagate it - // further (since we do no outbound RPCs anyway). - strict_policy = bio_get_uint32(msg); - bio_get_uint32(msg); // Ignore worksource header. - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - - if ((len != (sizeof(svcmgr_id) / 2)) || - memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { - fprintf(stderr,"invalid id %s\n", str8(s, len)); - return -1; - } - - if (sehandle && selinux_status_updated() > 0) { -#ifdef VENDORSERVICEMANAGER - struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle(); -#else - struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); -#endif - if (tmp_sehandle) { - selabel_close(sehandle); - sehandle = tmp_sehandle; - } - } - - switch(txn->code) { - case SVC_MGR_GET_SERVICE: - case SVC_MGR_CHECK_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid, - (const char*) txn_secctx->secctx); - if (!handle) - break; - bio_put_ref(reply, handle); - return 0; - - case SVC_MGR_ADD_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = bio_get_ref(msg); - allow_isolated = bio_get_uint32(msg) ? 1 : 0; - dumpsys_priority = bio_get_uint32(msg); - if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, - txn->sender_pid, (const char*) txn_secctx->secctx)) - return -1; - break; - - case SVC_MGR_LIST_SERVICES: { - uint32_t n = bio_get_uint32(msg); - uint32_t req_dumpsys_priority = bio_get_uint32(msg); - - if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { - ALOGE("list_service() uid=%d - PERMISSION DENIED\n", - txn->sender_euid); - return -1; - } - si = svclist; - // walk through the list of services n times skipping services that - // do not support the requested priority - while (si) { - if (si->dumpsys_priority & req_dumpsys_priority) { - if (n == 0) break; - n--; - } - si = si->next; - } - if (si) { - bio_put_string16(reply, si->name); - return 0; - } - return -1; - } - default: - ALOGE("unknown code %d\n", txn->code); - return -1; - } - - bio_put_uint32(reply, 0); - return 0; -} - - -static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len) -{ - struct audit_data *ad = (struct audit_data *)data; - - if (!ad || !ad->name) { - ALOGE("No service manager audit data"); - return 0; - } - - snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid); - return 0; -} - -int main(int argc, char** argv) -{ - struct binder_state *bs; - union selinux_callback cb; - char *driver; - - if (argc > 1) { - driver = argv[1]; - } else { - driver = "/dev/binder"; - } - - bs = binder_open(driver, 128*1024); - if (!bs) { -#ifdef VENDORSERVICEMANAGER - ALOGW("failed to open binder driver %s\n", driver); - while (true) { - sleep(UINT_MAX); - } -#else - ALOGE("failed to open binder driver %s\n", driver); -#endif - return -1; - } - - if (binder_become_context_manager(bs)) { - ALOGE("cannot become context manager (%s)\n", strerror(errno)); - return -1; - } - - cb.func_audit = audit_callback; - selinux_set_callback(SELINUX_CB_AUDIT, cb); -#ifdef VENDORSERVICEMANAGER - cb.func_log = selinux_vendor_log_callback; -#else - cb.func_log = selinux_log_callback; -#endif - selinux_set_callback(SELINUX_CB_LOG, cb); - -#ifdef VENDORSERVICEMANAGER - sehandle = selinux_android_vendor_service_context_handle(); -#else - sehandle = selinux_android_service_context_handle(); -#endif - selinux_status_open(true); - - if (sehandle == NULL) { - ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); - abort(); - } - - if (getcon(&service_manager_context) != 0) { - ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); - abort(); - } - - - binder_loop(bs, svcmgr_handler); - - return 0; -} diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp new file mode 100644 index 0000000000..812d5cacd5 --- /dev/null +++ b/cmds/servicemanager/test_sm.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 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 +#include +#include +#include + +#include "Access.h" +#include "ServiceManager.h" + +using android::sp; +using android::Access; +using android::IBinder; +using android::ServiceManager; +using android::os::IServiceManager; +using testing::_; +using testing::ElementsAre; +using testing::NiceMock; +using testing::Return; + +static sp getBinder() { + // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work. + // The context manager (servicemanager) is easy to get and is in another process. + return android::ProcessState::self()->getContextObject(nullptr); +} + +class MockAccess : public Access { +public: + MOCK_METHOD1(getCallingContext, CallingContext(const std::string& name)); + MOCK_METHOD1(canAdd, bool(const CallingContext&)); + MOCK_METHOD1(canFind, bool(const CallingContext&)); + MOCK_METHOD1(canList, bool(const CallingContext&)); +}; + +static sp getPermissiveServiceManager() { + std::unique_ptr access = std::make_unique>(); + + ON_CALL(*access, getCallingContext(_)).WillByDefault(Return(Access::CallingContext{})); + ON_CALL(*access, canAdd(_)).WillByDefault(Return(true)); + ON_CALL(*access, canFind(_)).WillByDefault(Return(true)); + ON_CALL(*access, canList(_)).WillByDefault(Return(true)); + + sp sm = new ServiceManager(std::move(access)); + return sm; +} + +TEST(AddService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, EmptyNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, JustShortEnoughServiceNameHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService(std::string(127, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, TooLongNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService(std::string(128, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddNullServiceDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("foo", nullptr, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddDisallowedFromApp) { + for (uid_t uid : { AID_APP_START, AID_APP_START + 1, AID_APP_END }) { + std::unique_ptr access = std::make_unique>(); + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{ + .debugPid = 1337, + .uid = uid, + })); + EXPECT_CALL(*access, canAdd(_)).Times(0); + sp sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + } + +} + +TEST(AddService, HappyOverExistingService) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, NoPermissions) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(false)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(GetService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out); +} + +TEST(GetService, NonExistant) { + auto sm = getPermissiveServiceManager(); + + sp out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, NoPermissionsForGettingService) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillRepeatedly(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(false)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, AllowedFromIsolated) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out.get()); +} + +TEST(GetService, NotAllowedFromIsolated) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + + // TODO(b/136023468): when security check is first, this should be called first + // EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(ListServices, NoPermissions) { + std::unique_ptr access = std::make_unique>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); + + sp sm = new ServiceManager(std::move(access)); + + std::vector out; + EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + EXPECT_TRUE(out.empty()); +} + +TEST(ListServices, AllServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa", "sb", "sc", "sd")); +} + +TEST(ListServices, CriticalServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa")); +} diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 905b25f397..760d55b751 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -94,7 +94,6 @@ cc_library_shared { "PermissionController.cpp", "ProcessInfoService.cpp", "IpPrefix.cpp", - ":libbinder_aidl", ], }, }, @@ -142,8 +141,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/os/IServiceManager.aidl", ], path: "aidl", } - -subdirs = ["tests"] diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index a2d10ab0ab..3424c28883 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1062,7 +1062,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, sp the_context_object; -void setTheContextObject(sp obj) +void IPCThreadState::setTheContextObject(sp obj) { the_context_object = obj; } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 0203d41992..07550fb571 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -18,6 +18,7 @@ #include +#include #include #include #ifndef __ANDROID_VNDK__ @@ -34,6 +35,9 @@ namespace android { +using AidlServiceManager = android::os::IServiceManager; +using android::binder::Status; + sp defaultServiceManager() { static Mutex gDefaultServiceManagerLock; @@ -142,11 +146,12 @@ class BpServiceManager : public BpInterface { public: explicit BpServiceManager(const sp& impl) - : BpInterface(impl) + : BpInterface(impl), + mTheRealServiceManager(interface_cast(impl)) { } - virtual sp getService(const String16& name) const + sp getService(const String16& name) const override { static bool gSystemBootCompleted = false; @@ -179,43 +184,36 @@ public: return nullptr; } - virtual sp checkService( const String16& name) const - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); - return reply.readStrongBinder(); + sp checkService(const String16& name) const override { + sp ret; + if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { + return nullptr; + } + return ret; } - virtual status_t addService(const String16& name, const sp& service, - bool allowIsolated, int dumpsysPriority) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - data.writeStrongBinder(service); - data.writeInt32(allowIsolated ? 1 : 0); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readExceptionCode() : err; + status_t addService(const String16& name, const sp& service, + bool allowIsolated, int dumpsysPriority) override { + Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority); + return status.exceptionCode(); } virtual Vector listServices(int dumpsysPriority) { - Vector res; - int n = 0; + std::vector ret; + if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { + return {}; + } - for (;;) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeInt32(n++); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); - if (err != NO_ERROR) - break; - res.add(reply.readString16()); + Vector res; + res.setCapacity(ret.size()); + for (const std::string& name : ret) { + res.push(String16(name.c_str())); } return res; } + +private: + sp mTheRealServiceManager; }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl new file mode 100644 index 0000000000..50a72aa9e4 --- /dev/null +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** + * Basic interface for finding and publishing system services. + * + * You likely want to use android.os.ServiceManager in Java or + * android::IServiceManager in C++ in order to use this interface. + * + * @hide + */ +interface IServiceManager { + /* + * Must update values in IServiceManager.h + */ + /* Allows services to dump sections according to priorities. */ + const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0 + const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1 + const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2 + /** + * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the + * same priority as NORMAL priority but the services are not called with dump priority + * arguments. + */ + const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3 + + const int DUMP_FLAG_PRIORITY_ALL = 15; + // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH + // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; + + /* Allows services to dump sections in protobuf format. */ + const int DUMP_FLAG_PROTO = 16; // 1 << 4 + + /** + * Retrieve an existing service called @a name from the + * service manager. + * + * This is the same as checkService (returns immediately) but + * exists for legacy purposes. + * + * Returns null if the service does not exist. + */ + @UnsupportedAppUsage + IBinder getService(@utf8InCpp String name); + + /** + * Retrieve an existing service called @a name from the service + * manager. Non-blocking. Returns null if the service does not + * exist. + */ + @UnsupportedAppUsage + IBinder checkService(@utf8InCpp String name); + + /** + * Place a new @a service called @a name into the service + * manager. + */ + void addService(@utf8InCpp String name, IBinder service, + boolean allowIsolated, int dumpPriority); + + /** + * Return a list of all currently running services. + */ + @utf8InCpp String[] listServices(int dumpPriority); +} diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 614b0b33dd..b810f7e8ee 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -110,6 +110,8 @@ public: // the maximum number of binder threads threads allowed for this process. void blockUntilThreadAvailable(); + // Service manager registration + void setTheContextObject(sp obj); // Is this thread currently serving a binder call. This method // returns true if while traversing backwards from the function call -- cgit v1.2.3-59-g8ed1b From 538cedc381f66f6b07265f82be65e5bc725c7e87 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 24 Jun 2019 19:35:03 -0700 Subject: BufferQueue: handle consumer driven size for pre-rotation This change adds an option for the producer to set auto pre-rotation on the buffers to be allocated. When auto pre-rotation is enabled, if the current buffer size is driven by the consumer and there's 90 or 270 degree rotation specified in the transform hint currently used by the producer, then the dimension of the buffers to be allocated will be additionally swapped upon buffers pre-allocaton or dequeueBuffer. Auto prerotaion will be cached at Surface producer side, and will be reset to false upon Surface disconnection. Bug: 129422697 Test: atest libgui_test:SurfaceTest#DequeueWithConsumerDrivenSize Change-Id: I01ddf3e00d5951935e557d18932ea9869f36b5d6 --- libs/gui/BufferQueueCore.cpp | 12 ++-- libs/gui/BufferQueueProducer.cpp | 31 +++++++++- libs/gui/IGraphicBufferProducer.cpp | 29 ++++++++++ libs/gui/Surface.cpp | 27 +++++++++ libs/gui/include/gui/BufferQueueCore.h | 8 +++ libs/gui/include/gui/BufferQueueProducer.h | 3 + libs/gui/include/gui/IGraphicBufferProducer.h | 8 +++ libs/gui/include/gui/Surface.h | 3 + libs/gui/tests/Surface_test.cpp | 70 ++++++++++++++++++++++ libs/nativewindow/ANativeWindow.cpp | 4 ++ libs/nativewindow/include/system/window.h | 83 ++++++++++++++++----------- libs/nativewindow/include/vndk/window.h | 9 +++ libs/nativewindow/libnativewindow.map.txt | 1 + services/surfaceflinger/MonitoredProducer.cpp | 4 ++ services/surfaceflinger/MonitoredProducer.h | 1 + 15 files changed, 253 insertions(+), 40 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index e0e3431ca5..b429d387ad 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -97,7 +97,9 @@ BufferQueueCore::BufferQueueCore() : mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN), mLastQueuedSlot(INVALID_BUFFER_SLOT), - mUniqueId(getUniqueId()) + mUniqueId(getUniqueId()), + mAutoPrerotation(false), + mTransformHintInUse(0) { int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { @@ -123,10 +125,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const mQueueBufferCanDrop, mLegacyBufferDrop); outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); - outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint, - mFrameCounter); + outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(), + mTransformHint, mFrameCounter); + outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(), + mTransformHintInUse, mAutoPrerotation); - outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..e05667e895 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -408,6 +408,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou if (useDefaultSize) { width = mCore->mDefaultWidth; height = mCore->mDefaultHeight; + if (mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(width, height); + } } int found = BufferItem::INVALID_BUFFER_SLOT; @@ -951,7 +955,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; @@ -1194,7 +1198,7 @@ status_t BufferQueueProducer::connect(const sp& listener, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; @@ -1298,6 +1302,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); mCore->mDequeueCondition.notify_all(); + mCore->mAutoPrerotation = false; listener = mCore->mConsumerListener; } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("disconnect: not connected (req=%d)", api); @@ -1341,6 +1346,8 @@ status_t BufferQueueProducer::setSidebandStream(const sp& stream) void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage) { ATRACE_CALL(); + + const bool useDefaultSize = !width && !height; while (true) { size_t newBufferCount = 0; uint32_t allocWidth = 0; @@ -1367,6 +1374,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocWidth = width > 0 ? width : mCore->mDefaultWidth; allocHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(allocWidth, allocHeight); + } + allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); @@ -1397,6 +1409,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, std::unique_lock lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(checkWidth, checkHeight); + } + PixelFormat checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; uint64_t checkUsage = usage | mCore->mConsumerUsageBits; @@ -1599,4 +1616,14 @@ status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { return NO_ERROR; } +status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + BQ_LOGV("setAutoPrerotation: %d", autoPrerotation); + + std::lock_guard lock(mCore->mMutex); + + mCore->mAutoPrerotation = autoPrerotation; + return NO_ERROR; +} + } // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0e03b7d393..0b8c70525b 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -73,6 +73,7 @@ enum { GET_UNIQUE_ID, GET_CONSUMER_USAGE, SET_LEGACY_BUFFER_DROP, + SET_AUTO_PREROTATION, }; class BpGraphicBufferProducer : public BpInterface @@ -547,6 +548,17 @@ public: } return actualResult; } + + virtual status_t setAutoPrerotation(bool autoPrerotation) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeBool(autoPrerotation); + status_t result = remote()->transact(SET_AUTO_PREROTATION, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -675,6 +687,10 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const override { return mBase->getConsumerUsage(outUsage); } + + status_t setAutoPrerotation(bool autoPrerotation) override { + return mBase->setAutoPrerotation(autoPrerotation); + } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, @@ -688,6 +704,12 @@ status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) { return INVALID_OPERATION; } +status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { + // No-op for IGBP other than BufferQueue. + (void)autoPrerotation; + return INVALID_OPERATION; +} + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1050,6 +1072,13 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case SET_AUTO_PREROTATION: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + bool autoPrerotation = data.readBool(); + status_t result = setAutoPrerotation(autoPrerotation); + reply->writeInt32(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e6eb327c6f..26b630fec6 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1072,6 +1072,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_CONSUMER_USAGE64: res = dispatchGetConsumerUsage64(args); break; + case NATIVE_WINDOW_SET_AUTO_PREROTATION: + res = dispatchSetAutoPrerotation(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1272,6 +1275,11 @@ int Surface::dispatchGetConsumerUsage64(va_list args) { return getConsumerUsage(usage); } +int Surface::dispatchSetAutoPrerotation(va_list args) { + bool autoPrerotation = va_arg(args, int); + return setAutoPrerotation(autoPrerotation); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -1339,6 +1347,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; + mAutoPrerotation = false; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; @@ -1941,4 +1950,22 @@ status_t Surface::attachAndQueueBuffer(Surface* surface, sp buffe return err; } +int Surface::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + ALOGV("Surface::setAutoPrerotation (%d)", autoPrerotation); + Mutex::Autolock lock(mMutex); + + if (mAutoPrerotation == autoPrerotation) { + return OK; + } + + status_t err = mGraphicBufferProducer->setAutoPrerotation(autoPrerotation); + if (err == NO_ERROR) { + mAutoPrerotation = autoPrerotation; + } + ALOGE_IF(err, "IGraphicBufferProducer::setAutoPrerotation(%d) returned %s", autoPrerotation, + strerror(-err)); + return err; +} + }; // namespace android diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 690a85f395..205e79c879 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -348,6 +348,14 @@ private: const uint64_t mUniqueId; + // When buffer size is driven by the consumer and mTransformHint specifies + // a 90 or 270 degree rotation, this indicates whether the width and height + // used by dequeueBuffer will be additionally swapped. + bool mAutoPrerotation; + + // mTransformHintInUse is to cache the mTransformHint used by the producer. + uint32_t mTransformHintInUse; + }; // class BufferQueueCore } // namespace android diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index d2a47a6aa8..9ad92a6e78 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -190,6 +190,9 @@ public: // See IGraphicBufferProducer::getConsumerUsage virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + // See IGraphicBufferProducer::setAutoPrerotation + virtual status_t setAutoPrerotation(bool autoPrerotation); + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp& who); diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..986adae864 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -629,6 +629,14 @@ public: // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + // Enable/disable the auto prerotation at buffer allocation when the buffer + // size is driven by the consumer. + // + // When buffer size is driven by the consumer and the transform hint + // specifies a 90 or 270 degree rotation, if auto prerotation is enabled, + // the width and height used for dequeueBuffer will be additionally swapped. + virtual status_t setAutoPrerotation(bool autoPrerotation); + // Static method exports any IGraphicBufferProducer object to a parcel. It // handles null producer as well. static status_t exportToParcel(const sp& producer, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0c471bb701..da0282c02e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -230,6 +230,7 @@ private: int dispatchGetWideColorSupport(va_list args); int dispatchGetHdrSupport(va_list args); int dispatchGetConsumerUsage64(va_list args); + int dispatchSetAutoPrerotation(va_list args); bool transformToDisplayInverse(); protected: @@ -265,6 +266,7 @@ public: virtual int setAsyncMode(bool async); virtual int setSharedBufferMode(bool sharedBufferMode); virtual int setAutoRefresh(bool autoRefresh); + virtual int setAutoPrerotation(bool autoPrerotation); virtual int setBuffersDimensions(uint32_t width, uint32_t height); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); @@ -433,6 +435,7 @@ protected: // Caches the values that have been passed to the producer. bool mSharedBufferMode; bool mAutoRefresh; + bool mAutoPrerotation; // If in shared buffer mode and auto refresh is enabled, store the shared // buffer slot and return it for all calls to queue/dequeue without going diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d3708586f5..7718bc1b8e 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1746,4 +1746,74 @@ TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { EXPECT_EQ(-1, outDisplayPresentTime); } +TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setDefaultBufferSize(10, 10); + + sp surface = new Surface(producer); + sp window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_set_buffers_dimensions(window.get(), 0, 0); + + int fence; + ANativeWindowBuffer* buffer; + + // Buffer size is driven by the consumer + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Buffer size is driven by the consumer + consumer->setDefaultBufferSize(10, 20); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Transform hint isn't synced to producer before queueBuffer or connect + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); + + // Transform hint is synced to producer but no auto prerotation + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Prerotation is driven by the consumer with the transform hint used by producer + native_window_set_auto_prerotation(window.get(), true); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(20, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Turn off auto prerotaton + native_window_set_auto_prerotation(window.get(), false); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Test auto prerotation bit is disabled after disconnect + native_window_set_auto_prerotation(window.get(), true); + native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + native_window_set_buffers_dimensions(window.get(), 0, 0); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); +} + } // namespace android diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 8435dac636..1751443419 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -262,3 +262,7 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) { return native_window_set_auto_refresh(window, autoRefresh); } + +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) { + return native_window_set_auto_prerotation(window, autoPrerotation); +} diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 61590e0196..8cbf0a4244 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -203,41 +203,42 @@ enum { */ enum { // clang-format off - NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ - NATIVE_WINDOW_CONNECT = 1, /* deprecated */ - NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ - NATIVE_WINDOW_SET_CROP = 3, /* private */ - NATIVE_WINDOW_SET_BUFFER_COUNT = 4, - NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ - NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, - NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, - NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, - NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, - NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ - NATIVE_WINDOW_LOCK = 11, /* private */ - NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ - NATIVE_WINDOW_API_CONNECT = 13, /* private */ - NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ - NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ - NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ - NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ - NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, - NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, - NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ - NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, - NATIVE_WINDOW_SET_AUTO_REFRESH = 22, - NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, - NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, - NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, - NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, - NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, - NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, - NATIVE_WINDOW_GET_HDR_SUPPORT = 29, - NATIVE_WINDOW_SET_USAGE64 = 30, - NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, - NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, - NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, + NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ + NATIVE_WINDOW_CONNECT = 1, /* deprecated */ + NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ + NATIVE_WINDOW_SET_CROP = 3, /* private */ + NATIVE_WINDOW_SET_BUFFER_COUNT = 4, + NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ + NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, + NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, + NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, + NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, + NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ + NATIVE_WINDOW_LOCK = 11, /* private */ + NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ + NATIVE_WINDOW_API_CONNECT = 13, /* private */ + NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ + NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ + NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ + NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ + NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, + NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, + NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ + NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, + NATIVE_WINDOW_SET_AUTO_REFRESH = 22, + NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, + NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, + NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, + NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, + NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, + NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, + NATIVE_WINDOW_GET_HDR_SUPPORT = 29, + NATIVE_WINDOW_SET_USAGE64 = 30, + NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, + NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, + NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, + NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, // clang-format on }; @@ -985,4 +986,18 @@ static inline int native_window_get_consumer_usage(struct ANativeWindow* window, return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage); } +/* + * native_window_set_auto_prerotation(..., autoPrerotation) + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +static inline int native_window_set_auto_prerotation(struct ANativeWindow* window, + bool autoPrerotation) { + return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation); +} + __END_DECLS diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h index 995ba44d20..500052c936 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -316,6 +316,15 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo */ int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh); +/* + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation); /*****************************************************************************/ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index bad8b11540..119a07dad7 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -28,6 +28,7 @@ LIBNATIVEWINDOW { ANativeWindow_queryf; # vndk ANativeWindow_queueBuffer; # vndk ANativeWindow_release; + ANativeWindow_setAutoPrerotation; # vndk ANativeWindow_setAutoRefresh; # vndk ANativeWindow_setBufferCount; # vndk ANativeWindow_setBuffersDataSpace; # introduced=28 diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index c60421b538..7a959f7b19 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -154,6 +154,10 @@ status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { return mProducer->getConsumerUsage(outUsage); } +status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) { + return mProducer->setAutoPrerotation(autoPrerotation); +} + IBinder* MonitoredProducer::onAsBinder() { return this; } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index d346f821d3..788919b3da 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -70,6 +70,7 @@ public: virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; virtual status_t getUniqueId(uint64_t* outId) const override; virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + virtual status_t setAutoPrerotation(bool autoPrerotation) override; // The Layer which created this producer, and on which queued Buffer's will be displayed. sp getLayer() const; -- cgit v1.2.3-59-g8ed1b From 8002fcab8445bf52b178691a13a67936c69c8035 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 28 Jun 2019 15:24:13 -0700 Subject: [SurfaceFlinger] Clean-up dead code * Remove methods that are no longer used. * Downgrade visibility of public RenderEngine methods that are currently unused. Test: builds Change-Id: I27d4e1cd7e88b1404d20149e9d0bc89f6cf1bde6 --- libs/renderengine/gl/GLESRenderEngine.cpp | 40 -------------- libs/renderengine/gl/GLESRenderEngine.h | 61 +++++++++------------- .../include/renderengine/RenderEngine.h | 56 -------------------- .../include/renderengine/mock/RenderEngine.h | 24 --------- services/surfaceflinger/BufferLayerConsumer.cpp | 24 --------- services/surfaceflinger/BufferLayerConsumer.h | 5 -- .../include/compositionengine/RenderSurface.h | 4 -- .../include/compositionengine/impl/RenderSurface.h | 1 - .../include/compositionengine/mock/RenderSurface.h | 1 - .../CompositionEngine/src/RenderSurface.cpp | 7 --- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 14 ----- services/surfaceflinger/Layer.cpp | 26 --------- services/surfaceflinger/Layer.h | 2 - services/surfaceflinger/SurfaceFlinger.cpp | 5 -- services/surfaceflinger/SurfaceFlinger.h | 1 - .../tests/unittests/CompositionTest.cpp | 5 -- 16 files changed, 26 insertions(+), 250 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 46a8e9eecf..6e7ec336e9 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -456,10 +456,6 @@ void GLESRenderEngine::primeCache() const { mFeatureFlags & USE_COLOR_MANAGEMENT); } -bool GLESRenderEngine::isCurrent() const { - return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext(); -} - base::unique_fd GLESRenderEngine::flush() { ATRACE_CALL(); if (!GLExtensions::getInstance().hasNativeFenceSync()) { @@ -795,7 +791,6 @@ status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", glStatus); @@ -1013,33 +1008,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return NO_ERROR; } -void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) { - setViewportAndProjection(Rect(vpw, vph), sourceCrop); - - if (rotation == ui::Transform::ROT_0) { - return; - } - - // Apply custom rotation to the projection. - float rot90InRadians = 2.0f * static_cast(M_PI) / 4.0f; - mat4 m = mState.projectionMatrix; - switch (rotation) { - case ui::Transform::ROT_90: - m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_180: - m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_270: - m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m; - break; - default: - break; - } - mState.projectionMatrix = m; -} - void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { ATRACE_CALL(); mVpWidth = viewport.getWidth(); @@ -1103,14 +1071,6 @@ void GLESRenderEngine::setupLayerTexturing(const Texture& texture) { mState.textureEnabled = true; } -void GLESRenderEngine::setupLayerBlackedOut() { - glBindTexture(GL_TEXTURE_2D, mProtectedTexName); - Texture texture(Texture::TEXTURE_2D, mProtectedTexName); - texture.setDimensions(1, 1); // FIXME: we should get that from somewhere - mState.texture = texture; - mState.textureEnabled = true; -} - void GLESRenderEngine::setColorTransform(const mat4& colorTransform) { mState.colorMatrix = colorTransform; } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index de793c2142..70b704abce 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -50,7 +50,6 @@ class GLESRenderEngine : public impl::RenderEngine { public: static std::unique_ptr create(int hwcFormat, uint32_t featureFlags, uint32_t imageCacheSize); - static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy, @@ -58,17 +57,7 @@ public: uint32_t imageCacheSize); ~GLESRenderEngine() override EXCLUDES(mRenderingMutex); - std::unique_ptr createFramebuffer() override; - std::unique_ptr createImage() override; - void primeCache() const override; - bool isCurrent() const override; - base::unique_fd flush() override; - bool finish() override; - bool waitFence(base::unique_fd fenceFd) override; - void clearWithColor(float red, float green, float blue, float alpha) override; - void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; void bindExternalTextureImage(uint32_t texName, const Image& image) override; @@ -78,7 +67,6 @@ public: void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); status_t bindFrameBuffer(Framebuffer* framebuffer) override; void unbindFrameBuffer(Framebuffer* framebuffer) override; - void checkErrors() const override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -88,9 +76,7 @@ public: base::unique_fd&& bufferFence, base::unique_fd* drawFence) EXCLUDES(mRenderingMutex) override; - // internal to RenderEngine EGLDisplay getEGLDisplay() const { return mEGLDisplay; } - EGLConfig getEGLConfig() const { return mEGLConfig; } // Creates an output image for rendering to EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, bool useFramebufferCache); @@ -104,27 +90,6 @@ public: protected: Framebuffer* getFramebufferForDrawing() override; void dump(std::string& result) override; - void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) override; - void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) override; - void setupLayerTexturing(const Texture& texture) override; - void setupLayerBlackedOut() override; - void setupFillWithColor(float r, float g, float b, float a) override; - void setColorTransform(const mat4& colorTransform) override; - void disableTexturing() override; - void disableBlending() override; - void setupCornerRadiusCropSize(float width, float height) override; - - // HDR and color management related functions and state - void setSourceY410BT2020(bool enable) override; - void setSourceDataSpace(ui::Dataspace source) override; - void setOutputDataSpace(ui::Dataspace dataspace) override; - void setDisplayMaxLuminance(const float maxLuminance) override; - - // drawing - void drawMesh(const Mesh& mesh) override; - size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -136,12 +101,16 @@ private: GLES_VERSION_3_0 = 0x30000, }; + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); static GlesVersion parseGlesVersion(const char* str); static EGLContext createEglContext(EGLDisplay display, EGLConfig config, EGLContext shareContext, bool useContextPriority, Protection protection); static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection); + std::unique_ptr createFramebuffer(); + std::unique_ptr createImage(); + void checkErrors() const; void setScissor(const Rect& region); void disableScissor(); bool waitSync(EGLSyncKHR sync, EGLint flags); @@ -165,6 +134,28 @@ private: // blending is an expensive operation, we want to turn off blending when it's not necessary. void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer, const Mesh& mesh); + base::unique_fd flush(); + bool finish(); + bool waitFence(base::unique_fd fenceFd); + void clearWithColor(float red, float green, float blue, float alpha); + void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha); + void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, + const half4& color, float cornerRadius); + void setupLayerTexturing(const Texture& texture); + void setupFillWithColor(float r, float g, float b, float a); + void setColorTransform(const mat4& colorTransform); + void disableTexturing(); + void disableBlending(); + void setupCornerRadiusCropSize(float width, float height); + + // HDR and color management related functions and state + void setSourceY410BT2020(bool enable); + void setSourceDataSpace(ui::Dataspace source); + void setOutputDataSpace(ui::Dataspace dataspace); + void setDisplayMaxLuminance(const float maxLuminance); + + // drawing + void drawMesh(const Mesh& mesh); EGLDisplay mEGLDisplay; EGLConfig mEGLConfig; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index e7070041f2..8a798eefd1 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -77,10 +77,6 @@ public: // This interface, while still in use until a suitable replacement is built, // should be considered deprecated, minus some methods which still may be // used to support legacy behavior. - - virtual std::unique_ptr createFramebuffer() = 0; - virtual std::unique_ptr createImage() = 0; - virtual void primeCache() const = 0; // dump the extension strings. always call the base class. @@ -88,24 +84,6 @@ public: virtual bool useNativeFenceSync() const = 0; virtual bool useWaitSync() const = 0; - - virtual bool isCurrent() const = 0; - - // helpers - // flush submits RenderEngine command stream for execution and returns a - // native fence fd that is signaled when the execution has completed. It - // returns -1 on errors. - virtual base::unique_fd flush() = 0; - // finish waits until RenderEngine command stream has been executed. It - // returns false on errors. - virtual bool finish() = 0; - // waitFence inserts a wait on an external fence fd to RenderEngine - // command stream. It returns false on errors. - virtual bool waitFence(base::unique_fd fenceFd) = 0; - - virtual void clearWithColor(float red, float green, float blue, float alpha) = 0; - virtual void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) = 0; virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0; @@ -126,40 +104,6 @@ public: virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0; virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0; - // set-up - virtual void checkErrors() const = 0; - virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) = 0; - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) = 0; - virtual void setupLayerTexturing(const Texture& texture) = 0; - virtual void setupLayerBlackedOut() = 0; - virtual void setupFillWithColor(float r, float g, float b, float a) = 0; - // Sets up the crop size for corner radius clipping. - // - // Having corner radius will force GPU composition on the layer and its children, drawing it - // with a special shader. The shader will receive the radius and the crop rectangle as input, - // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1. - // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop - // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be - // in local layer coordinate space, so we have to take the layer transform into account when - // walking up the tree. - virtual void setupCornerRadiusCropSize(float width, float height) = 0; - - // Set a color transform matrix that is applied in linear space right before OETF. - virtual void setColorTransform(const mat4& /* colorTransform */) = 0; - virtual void disableTexturing() = 0; - virtual void disableBlending() = 0; - - // HDR and color management support - virtual void setSourceY410BT2020(bool enable) = 0; - virtual void setSourceDataSpace(ui::Dataspace source) = 0; - virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0; - virtual void setDisplayMaxLuminance(const float maxLuminance) = 0; - - // drawing - virtual void drawMesh(const Mesh& mesh) = 0; - // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index e33bcfd994..f099cd2455 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -34,20 +34,12 @@ public: RenderEngine(); ~RenderEngine() override; - MOCK_METHOD0(createFramebuffer, std::unique_ptr()); - MOCK_METHOD0(createImage, std::unique_ptr()); MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*()); MOCK_CONST_METHOD0(primeCache, void()); MOCK_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(useNativeFenceSync, bool()); MOCK_CONST_METHOD0(useWaitSync, bool()); MOCK_CONST_METHOD0(isCurrent, bool()); - MOCK_METHOD0(flush, base::unique_fd()); - MOCK_METHOD0(finish, bool()); - MOCK_METHOD1(waitFence, bool(base::unique_fd*)); - bool waitFence(base::unique_fd fd) override { return waitFence(&fd); }; - MOCK_METHOD4(clearWithColor, void(float, float, float, float)); - MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&)); @@ -55,22 +47,6 @@ public: MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, const sp&, const sp&)); MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); - MOCK_CONST_METHOD0(checkErrors, void()); - MOCK_METHOD4(setViewportAndProjection, - void(size_t, size_t, Rect, ui::Transform::orientation_flags)); - MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float)); - MOCK_METHOD1(setupLayerTexturing, void(const Texture&)); - MOCK_METHOD0(setupLayerBlackedOut, void()); - MOCK_METHOD4(setupFillWithColor, void(float, float, float, float)); - MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float)); - MOCK_METHOD1(setColorTransform, void(const mat4&)); - MOCK_METHOD1(setSaturationMatrix, void(const mat4&)); - MOCK_METHOD0(disableTexturing, void()); - MOCK_METHOD0(disableBlending, void()); - MOCK_METHOD1(setSourceY410BT2020, void(bool)); - MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setDisplayMaxLuminance, void(const float)); MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*)); MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 6709fb4b48..096cd1a9cc 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -419,30 +419,6 @@ std::shared_ptr BufferLayerConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t BufferLayerConsumer::doFenceWaitLocked() const { - if (mCurrentFence->isValid()) { - if (mRE.useWaitSync()) { - base::unique_fd fenceFd(mCurrentFence->dup()); - if (fenceFd == -1) { - BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno); - return -errno; - } - if (!mRE.waitFence(std::move(fenceFd))) { - BLC_LOGE("doFenceWait: failed to wait on fence fd"); - return UNKNOWN_ERROR; - } - } else { - status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked"); - if (err != NO_ERROR) { - BLC_LOGE("doFenceWait: error waiting for fence: %d", err); - return err; - } - } - } - - return NO_ERROR; -} - void BufferLayerConsumer::freeBufferLocked(int slotIndex) { BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); std::lock_guard lock(mImagesMutex); diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index e3f6100c35..144686c83d 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -252,11 +252,6 @@ private: // mCurrentTextureImage must not be nullptr. void computeCurrentTransformMatrixLocked(); - // doFenceWaitLocked inserts a wait command into the RenderEngine command - // stream to ensure that it is safe for future RenderEngine commands to - // access the current texture buffer. - status_t doFenceWaitLocked() const; - // getCurrentCropLocked returns the cropping rectangle of the current buffer. Rect getCurrentCropLocked() const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index e21128ca81..9bff73e950 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -83,10 +83,6 @@ public: // Called after the HWC calls are made to present the display virtual void onPresentDisplayCompleted() = 0; - // Called to set the viewport and projection state for rendering into this - // surface - virtual void setViewportAndProjection() = 0; - // Called after the surface has been rendering to signal the surface should // be made ready for displaying virtual void flip() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 0f57315eb6..e4c9c80429 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -56,7 +56,6 @@ public: sp dequeueBuffer(base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd&& readyFence) override; void onPresentDisplayCompleted() override; - void setViewportAndProjection() override; void flip() override; // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index ca2299aa26..146a2eae64 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -41,7 +41,6 @@ public: MOCK_METHOD1(dequeueBuffer, sp(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd&&)); MOCK_METHOD0(onPresentDisplayCompleted, void()); - MOCK_METHOD0(setViewportAndProjection, void()); MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 3fcd9d155d..8a91316e65 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -215,13 +215,6 @@ void RenderSurface::onPresentDisplayCompleted() { mDisplaySurface->onFrameCommitted(); } -void RenderSurface::setViewportAndProjection() { - auto& renderEngine = mCompositionEngine.getRenderEngine(); - Rect sourceCrop = Rect(mSize); - renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop, - ui::Transform::ROT_0); -} - void RenderSurface::flip() { mPageFlipCount++; } diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index f75a4dcb85..87419ea6a8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -363,20 +363,6 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) { mSurface.onPresentDisplayCompleted(); } -/* ------------------------------------------------------------------------ - * RenderSurface::setViewportAndProjection() - */ - -TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) { - mSurface.setSizeForTest(ui::Size(100, 200)); - - EXPECT_CALL(mRenderEngine, - setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0)) - .Times(1); - - mSurface.setViewportAndProjection(); -} - /* ------------------------------------------------------------------------ * RenderSurface::flip() */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b2df91d4ea..83ab5cfce2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -619,32 +619,6 @@ bool Layer::addSyncPoint(const std::shared_ptr& point) { // local state // ---------------------------------------------------------------------------- -void Layer::computeGeometry(const RenderArea& renderArea, - renderengine::Mesh& mesh, - bool useIdentityTransform) const { - const ui::Transform renderAreaTransform(renderArea.getTransform()); - FloatRect win = getBounds(); - - vec2 lt = vec2(win.left, win.top); - vec2 lb = vec2(win.left, win.bottom); - vec2 rb = vec2(win.right, win.bottom); - vec2 rt = vec2(win.right, win.top); - - ui::Transform layerTransform = getTransform(); - if (!useIdentityTransform) { - lt = layerTransform.transform(lt); - lb = layerTransform.transform(lb); - rb = layerTransform.transform(rb); - rt = layerTransform.transform(rt); - } - - renderengine::Mesh::VertexArray position(mesh.getPositionArray()); - position[0] = renderAreaTransform.transform(lt); - position[1] = renderAreaTransform.transform(lb); - position[2] = renderAreaTransform.transform(rb); - position[3] = renderAreaTransform.transform(rt); -} - bool Layer::isSecure() const { const State& s(mDrawingState); return (s.flags & layer_state_t::eLayerSecure); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 6db6beb4f6..8a4d87f889 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -357,8 +357,6 @@ public: return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); } - void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh, - bool useIdentityTransform) const; FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e5896f9985..2cb2544448 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3534,11 +3534,6 @@ bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, return true; } -void SurfaceFlinger::drawWormhole(const Region& region) const { - auto& engine(getRenderEngine()); - engine.fillRegionWithColor(region, 0, 0, 0, 0); -} - status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, const sp& parentHandle, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6d4b2d755c..1a9dcdd2ef 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -790,7 +790,6 @@ private: void postFramebuffer(const sp& display); void postFrame(); - void drawWormhole(const Region& region) const; /* ------------------------------------------------------------------------ * Display management diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4f8ed1ae1c..e6211c488e 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -303,11 +303,6 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1); EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true)); - // TODO: remove once we verify that we can just grab the fence from the - // FramebufferSurface. - EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() { - return base::unique_fd(); - })); EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1); EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1); -- cgit v1.2.3-59-g8ed1b From 83e514e303ffb18557984a89fbd3f0bbaac498ee Mon Sep 17 00:00:00 2001 From: Tianyu Jiang Date: Wed, 15 May 2019 15:05:30 -0700 Subject: Add GraphicBuffer over binder test and fix a crash in unflatten logic Test: GraphicBuffer_test GraphicBufferOverBinder_test Bug: None Change-Id: Idf00fcb740661adc1e1bb41dc2d78ece4f589c95 --- libs/ui/BufferHubBuffer.cpp | 1 + libs/ui/GraphicBuffer.cpp | 2 +- libs/ui/tests/Android.bp | 18 +++ libs/ui/tests/GraphicBufferOverBinder_test.cpp | 170 +++++++++++++++++++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 libs/ui/tests/GraphicBufferOverBinder_test.cpp (limited to 'libs') diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp index da91a979fe..1dfc1e9e88 100644 --- a/libs/ui/BufferHubBuffer.cpp +++ b/libs/ui/BufferHubBuffer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define LOG_TAG "BufferHubBuffer" #include #include diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 3fc6a2d34a..579e68e917 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -626,7 +626,7 @@ status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& si bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage, bufferHubBuffer->desc().stride); mBufferId = bufferHubBuffer->id(); - mBufferHubBuffer.reset(std::move(bufferHubBuffer.get())); + mBufferHubBuffer = std::move(bufferHubBuffer); return NO_ERROR; } diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 373fa4f221..c5170d091c 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -46,6 +46,24 @@ cc_test { cflags: ["-Wall", "-Werror"], } +// This test has a main method, and requires a separate binary to be built. +cc_test { + name: "GraphicBufferOverBinder_test", + srcs: ["GraphicBufferOverBinder_test.cpp"], + cflags: ["-Wall", "-Werror"], + header_libs: [ + "libdvr_headers", + ], + shared_libs: [ + "android.frameworks.bufferhub@1.0", + "libbinder", + "libgui", + "liblog", + "libui", + "libutils", + ], +} + cc_test { name: "BufferHub_test", header_libs: [ diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp new file mode 100644 index 0000000000..7c0a44a64f --- /dev/null +++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2019 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 "GraphicBufferOverBinder_test" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +constexpr uint32_t kTestWidth = 1024; +constexpr uint32_t kTestHeight = 1; +constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB; +constexpr uint32_t kTestLayerCount = 1; +constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; +static const String16 kTestServiceName = String16("GraphicBufferOverBinderTestService"); +enum GraphicBufferOverBinderTestServiceCode { + GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER, +}; + +class GraphicBufferOverBinderTestService : public BBinder { +public: + GraphicBufferOverBinderTestService() { + // GraphicBuffer + mGraphicBuffer = new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, + kTestUsage); + ALOGI("mGraphicBuffer id %" PRIi32, mGraphicBuffer->getBufferId()); + + // BufferHub-backed GraphicBuffer + std::unique_ptr bufferHubBuffer = + BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, + kTestUsage, /*userMetadataSize=*/0); + mBufferhubBackedGraphicBuffer = new GraphicBuffer(std::move(bufferHubBuffer)); + if (!mBufferhubBackedGraphicBuffer->isBufferHubBuffer()) { + ALOGE("Failed to back GraphicBuffer with BufferHub."); + } + if (bufferHubBuffer != nullptr) { + ALOGE("Failed to move BufferHubBuffer to GraphicBuffer"); + } + ALOGI("mBufferhubBackedGraphicBuffer id %" PRIi32, + mBufferhubBackedGraphicBuffer->getBufferId()); + } + + ~GraphicBufferOverBinderTestService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply, + uint32_t /*flags*/ = 0) { + switch (code) { + case GRAPHIC_BUFFER: { + return reply->write(*mGraphicBuffer); + } + case GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER: { + return reply->write(*mBufferhubBackedGraphicBuffer); + } + default: + return UNKNOWN_TRANSACTION; + }; + } + +protected: + sp mGraphicBuffer; + sp mBufferhubBackedGraphicBuffer; +}; + +static int runBinderServer() { + ProcessState::self()->startThreadPool(); + + sp sm = defaultServiceManager(); + sp service = new GraphicBufferOverBinderTestService; + sm->addService(kTestServiceName, service, false); + + ALOGI("Binder server running..."); + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + ALOGI("Binder server exiting..."); + return 0; +} + +class GraphicBufferOverBinderTest : public ::testing::TestWithParam { +protected: + virtual void SetUp() { + mService = defaultServiceManager()->getService(kTestServiceName); + if (mService == nullptr) { + ALOGE("Failed to connect to the test service."); + return; + } + + ALOGI("Binder service is ready for client."); + } + + status_t GetGraphicBuffer(sp* outBuf, uint32_t opCode) { + Parcel data; + Parcel reply; + status_t error = mService->transact(opCode, data, &reply); + if (error != NO_ERROR) { + ALOGE("Failed to get graphic buffer over binder, error=%d.", error); + return error; + } + + *outBuf = new GraphicBuffer(); + return reply.read(**outBuf); + } + +private: + sp mService; +}; + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferOverBinder) { + sp gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER), OK); + EXPECT_NE(gb, nullptr); + EXPECT_FALSE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferFromBufferHubBufferOverBinder) { + sp gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER), NO_ERROR); + EXPECT_NE(gb, nullptr); + EXPECT_TRUE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +} // namespace android + +int main(int argc, char** argv) { + pid_t pid = fork(); + if (pid == 0) { + android::ProcessState::self()->startThreadPool(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + + } else { + ALOGI("Test process pid: %d.", pid); + return android::runBinderServer(); + } +} -- cgit v1.2.3-59-g8ed1b From ff7bf701ad4a66ee4b9fe54c41e24fb5099fb533 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 5 Jun 2019 18:27:47 -0700 Subject: libtimeinstate: add more tests Check reported values to confirm that getUidCpuFreqTimes() and getUidsCpuFreqTimes() are behaving reasonably. Also revise RemoveUid test to create and then delete map entries for an unused UID rather than UID 0. getUidCpuFreqTimes() is only meant to be called when an app is uninstalled, and calling it with a UID that has running tasks creates data inconsistencies that can cause the new tests to fail. Since the revised test needs to directly manipulate the BPF map in order to add a fake entry, move some definitions from cputimeinstate.cpp into a header file to make them available for the test. Test: libtimeinstate_test passes Bug: 78498733 Change-Id: I1587b1c7db870343ff863f2156b2a810d8ace915 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/Android.bp | 4 ++ libs/cputimeinstate/cputimeinstate.cpp | 12 +--- libs/cputimeinstate/testtimeinstate.cpp | 112 +++++++++++++++++++++++++++++--- libs/cputimeinstate/timeinstate.h | 28 ++++++++ 4 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 libs/cputimeinstate/timeinstate.h (limited to 'libs') diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp index 28cb13827d..9080ce13db 100644 --- a/libs/cputimeinstate/Android.bp +++ b/libs/cputimeinstate/Android.bp @@ -19,7 +19,11 @@ cc_test { name: "libtimeinstate_test", srcs: ["testtimeinstate.cpp"], shared_libs: [ + "libbase", + "libbpf", + "libbpf_android", "libtimeinstate", + "libnetdutils", ], cflags: [ "-Werror", diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 41cbde1c18..0e68e628b6 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "libtimeinstate" #include "cputimeinstate.h" +#include "timeinstate.h" #include #include @@ -38,23 +39,12 @@ #include #include -#define BPF_FS_PATH "/sys/fs/bpf/" - using android::base::StringPrintf; using android::base::unique_fd; namespace android { namespace bpf { -struct time_key_t { - uint32_t uid; - uint32_t freq; -}; - -struct val_t { - uint64_t ar[100]; -}; - static std::mutex gInitializedMutex; static bool gInitialized = false; static uint32_t gNPolicies = 0; diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index d4b87386e0..6347de166a 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -1,14 +1,24 @@ +#include "timeinstate.h" + +#include + #include #include #include +#include +#include #include +#include namespace android { namespace bpf { +static constexpr uint64_t NSEC_PER_SEC = 1000000000; +static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365; + using std::vector; TEST(TimeInStateTest, SingleUid) { @@ -33,8 +43,95 @@ TEST(TimeInStateTest, AllUid) { } } +TEST(TimeInStateTest, SingleAndAllUidConsistent) { + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidCpuFreqTimes(uid); + ASSERT_TRUE(times2.has_value()); + + ASSERT_EQ(times1.size(), times2->size()); + for (uint32_t i = 0; i < times1.size(); ++i) { + ASSERT_EQ(times1[i].size(), (*times2)[i].size()); + for (uint32_t j = 0; j < times1[i].size(); ++j) { + ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC); + } + } + } +} + +void TestCheckDelta(uint64_t before, uint64_t after) { + // Times should never decrease + ASSERT_LE(before, after); + // UID can't have run for more than ~1s on each CPU + ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf()); +} + +TEST(TimeInStateTest, AllUidMonotonic) { + auto map1 = getUidsCpuFreqTimes(); + ASSERT_TRUE(map1.has_value()); + sleep(1); + auto map2 = getUidsCpuFreqTimes(); + ASSERT_TRUE(map2.has_value()); + + for (const auto &kv : *map1) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(map2->find(uid), map2->end()); + for (uint32_t policy = 0; policy < times.size(); ++policy) { + for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) { + auto before = times[policy][freqIdx]; + auto after = (*map2)[uid][policy][freqIdx]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + } + } +} + +TEST(TimeInStateTest, AllUidSanityCheck) { + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); + + bool foundLargeValue = false; + for (const auto &kv : *map) { + for (const auto &timeVec : kv.second) { + for (const auto &time : timeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) foundLargeValue = true; + } + } + } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(foundLargeValue); +} + TEST(TimeInStateTest, RemoveUid) { - auto times = getUidCpuFreqTimes(0); + uint32_t uid = 0; + { + // Find an unused UID + auto times = getUidsCpuFreqTimes(); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); + for (const auto &kv : *times) uid = std::max(uid, kv.first); + ++uid; + } + { + // Add a map entry for our fake UID by copying a real map entry + android::base::unique_fd fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; + ASSERT_GE(fd, 0); + time_key_t k; + ASSERT_FALSE(getFirstMapKey(fd, &k)); + val_t val; + ASSERT_FALSE(findMapEntry(fd, &k, &val)); + k.uid = uid; + ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST)); + } + auto times = getUidCpuFreqTimes(uid); ASSERT_TRUE(times.has_value()); ASSERT_FALSE(times->empty()); @@ -44,15 +141,12 @@ TEST(TimeInStateTest, RemoveUid) { } ASSERT_GT(sum, (uint64_t)0); - ASSERT_TRUE(clearUidCpuFreqTimes(0)); + ASSERT_TRUE(clearUidCpuFreqTimes(uid)); - auto times2 = getUidCpuFreqTimes(0); - ASSERT_TRUE(times2.has_value()); - ASSERT_EQ(times2->size(), times->size()); - for (size_t i = 0; i < times->size(); ++i) { - ASSERT_EQ((*times2)[i].size(), (*times)[i].size()); - for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]); - } + auto allTimes = getUidsCpuFreqTimes(); + ASSERT_TRUE(allTimes.has_value()); + ASSERT_FALSE(allTimes->empty()); + ASSERT_EQ(allTimes->find(uid), allTimes->end()); } } // namespace bpf diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h new file mode 100644 index 0000000000..cf66ae7077 --- /dev/null +++ b/libs/cputimeinstate/timeinstate.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define BPF_FS_PATH "/sys/fs/bpf/" + +struct time_key_t { + uint32_t uid; + uint32_t freq; +}; + +struct val_t { + uint64_t ar[100]; +}; -- cgit v1.2.3-59-g8ed1b From 27ab3ac610954ac01a18a1cf8559827cf7679f99 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 2 Jul 2019 18:10:55 -0700 Subject: GpuStats: move GpuStats related structs and enums away from GraphicsEnv Bug: 135210726 Test: build, flash and boot Test: adb shell dumpsys gpu Change-Id: I48c5c432aca916f923ab5674f8ec533d4f5aac0f --- libs/graphicsenv/GraphicsEnv.cpp | 38 +++++++------- libs/graphicsenv/IGpuService.cpp | 4 +- .../graphicsenv/include/graphicsenv/GpuStatsInfo.h | 39 ++++++++++++++ libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 59 +++------------------- libs/graphicsenv/include/graphicsenv/IGpuService.h | 2 +- opengl/libs/EGL/Loader.cpp | 12 ++--- services/gpuservice/GpuService.cpp | 2 +- services/gpuservice/GpuService.h | 2 +- services/gpuservice/gpustats/GpuStats.cpp | 26 +++++----- services/gpuservice/gpustats/GpuStats.h | 2 +- vulkan/libvulkan/driver.cpp | 10 ++-- 11 files changed, 94 insertions(+), 102 deletions(-) (limited to 'libs') diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 24b6c2d6de..a411dd56f6 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -170,11 +170,11 @@ void GraphicsEnv::hintActivityLaunch() { std::lock_guard lock(mStatsLock); if (mGpuStats.glDriverToSend) { mGpuStats.glDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime); + sendGpuStatsLocked(GpuStatsInfo::Api::API_GL, true, mGpuStats.glDriverLoadingTime); } if (mGpuStats.vkDriverToSend) { mGpuStats.vkDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); + sendGpuStatsLocked(GpuStatsInfo::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); } }); trySendGpuStatsThread.detach(); @@ -205,32 +205,32 @@ void GraphicsEnv::setGpuStats(const std::string& driverPackageName, mGpuStats.vulkanVersion = vulkanVersion; } -void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { +void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { ATRACE_CALL(); std::lock_guard lock(mStatsLock); switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: - case GraphicsEnv::Driver::ANGLE: { - if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) { + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::ANGLE: { + if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE) { mGpuStats.glDriverToLoad = driver; break; } - if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) { + if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) { mGpuStats.glDriverFallback = driver; } break; } - case Driver::VULKAN: - case Driver::VULKAN_UPDATED: { - if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) { + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: { + if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE) { mGpuStats.vkDriverToLoad = driver; break; } - if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) { + if (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE) { mGpuStats.vkDriverFallback = driver; } break; @@ -240,13 +240,13 @@ void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { } } -void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isDriverLoaded, +void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); std::lock_guard lock(mStatsLock); const bool doNotSend = mGpuStats.appPackageName.empty(); - if (api == GraphicsEnv::Api::API_GL) { + if (api == GpuStatsInfo::Api::API_GL) { if (doNotSend) mGpuStats.glDriverToSend = true; mGpuStats.glDriverLoadingTime = driverLoadingTime; } else { @@ -278,7 +278,7 @@ void GraphicsEnv::setCpuVulkanInUse() { } } -void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded, +void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); @@ -299,16 +299,16 @@ void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded, mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(), mGpuStats.vulkanVersion, static_cast(api), isDriverLoaded, driverLoadingTime); - GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE; + GpuStatsInfo::Driver driver = GpuStatsInfo::Driver::NONE; bool isIntendedDriverLoaded = false; - if (api == GraphicsEnv::Api::API_GL) { + if (api == GpuStatsInfo::Api::API_GL) { driver = mGpuStats.glDriverToLoad; isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE); + isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE); } else { driver = mGpuStats.vkDriverToLoad; isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE); + isDriverLoaded && (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE); } const sp gpuService = getGpuService(); diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 5f9624918f..30e5370650 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -30,7 +30,7 @@ public: virtual void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); @@ -143,7 +143,7 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep if ((status = data.readInt64(&driverLoadingTime)) != OK) return status; setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime, - appPackageName, vulkanVersion, static_cast(driver), + appPackageName, vulkanVersion, static_cast(driver), isDriverLoaded, driverLoadingTime); return OK; diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index edcccfea4a..c2fd10ae63 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -72,4 +72,43 @@ public: bool cpuVulkanInUse = false; }; +/* + * class for holding the gpu stats in GraphicsEnv before sending to GpuService. + */ +class GpuStatsInfo { +public: + enum Api { + API_GL = 0, + API_VK = 1, + }; + + enum Driver { + NONE = 0, + GL = 1, + GL_UPDATED = 2, + VULKAN = 3, + VULKAN_UPDATED = 4, + ANGLE = 5, + }; + + GpuStatsInfo() = default; + GpuStatsInfo(const GpuStatsInfo&) = default; + virtual ~GpuStatsInfo() = default; + + std::string driverPackageName = ""; + std::string driverVersionName = ""; + uint64_t driverVersionCode = 0; + int64_t driverBuildTime = 0; + 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; + bool vkDriverToSend = false; + int64_t glDriverLoadingTime = 0; + int64_t vkDriverLoadingTime = 0; +}; + } // namespace android diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index f5d19db493..aa14059d72 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -17,6 +17,8 @@ #ifndef ANDROID_UI_GRAPHICS_ENV_H #define ANDROID_UI_GRAPHICS_ENV_H 1 +#include + #include #include #include @@ -28,55 +30,6 @@ namespace android { struct NativeLoaderNamespace; class GraphicsEnv { -public: - enum Api { - API_GL = 0, - API_VK = 1, - }; - - enum Driver { - NONE = 0, - GL = 1, - GL_UPDATED = 2, - VULKAN = 3, - VULKAN_UPDATED = 4, - ANGLE = 5, - }; - -private: - struct GpuStats { - std::string driverPackageName; - std::string driverVersionName; - uint64_t driverVersionCode; - int64_t driverBuildTime; - std::string appPackageName; - int32_t vulkanVersion; - Driver glDriverToLoad; - Driver glDriverFallback; - Driver vkDriverToLoad; - Driver vkDriverFallback; - bool glDriverToSend; - bool vkDriverToSend; - int64_t glDriverLoadingTime; - int64_t vkDriverLoadingTime; - - GpuStats() - : driverPackageName(""), - driverVersionName(""), - driverVersionCode(0), - driverBuildTime(0), - appPackageName(""), - vulkanVersion(0), - glDriverToLoad(Driver::NONE), - glDriverFallback(Driver::NONE), - vkDriverToLoad(Driver::NONE), - vkDriverFallback(Driver::NONE), - glDriverToSend(false), - vkDriverToSend(false), - glDriverLoadingTime(0), - vkDriverLoadingTime(0) {} - }; - public: static GraphicsEnv& getInstance(); @@ -97,9 +50,9 @@ public: uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); void setCpuVulkanInUse(); - void setDriverToLoad(Driver driver); - void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime); - void sendGpuStatsLocked(Api api, bool isDriverLoaded, int64_t driverLoadingTime); + void setDriverToLoad(GpuStatsInfo::Driver driver); + void setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); + void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); bool shouldUseAngle(std::string appName); bool shouldUseAngle(); @@ -135,7 +88,7 @@ private: std::string mDriverPath; std::string mSphalLibraries; std::mutex mStatsLock; - GpuStats mGpuStats; + GpuStatsInfo mGpuStats; std::string mAnglePath; std::string mAngleAppName; std::string mAngleDeveloperOptIn; diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index 34f1c7ee7e..a47bbafcc4 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -37,7 +37,7 @@ public: virtual void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) = 0; // set CPU Vulkan in use signal from GraphicsEnvironment. diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 038a432337..23e11a82ac 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -311,7 +311,7 @@ void* Loader::open(egl_connection_t* cnx) } if (!hnd) { - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, false, systemTime() - openTime); } @@ -330,7 +330,7 @@ void* Loader::open(egl_connection_t* cnx) } if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) { - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, false, systemTime() - openTime); } @@ -340,7 +340,7 @@ void* Loader::open(egl_connection_t* cnx) LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1, "couldn't load system OpenGL ES wrapper libraries"); - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, true, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true, systemTime() - openTime); return (void*)hnd; @@ -637,7 +637,7 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { return nullptr; } - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::ANGLE); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); driver_t* hnd = nullptr; // ANGLE doesn't ship with GLES library, and thus we skip GLES driver. @@ -666,7 +666,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) } ALOGD("Load updated gl driver."); - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL_UPDATED); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL_UPDATED); driver_t* hnd = nullptr; void* dso = load_updated_driver("GLES", ns); if (dso) { @@ -697,7 +697,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact) { ATRACE_CALL(); - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL); driver_t* hnd = nullptr; void* dso = load_system_driver("GLES", suffix, exact); if (dso) { diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 8accf9d450..72757dd02b 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -51,7 +51,7 @@ GpuService::GpuService() : mGpuStats(std::make_unique()){}; void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 822690134a..3e0e1b5f9b 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -46,7 +46,7 @@ private: void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) override; status_t getGpuStatsGlobalInfo(std::vector* outStats) const override; status_t getGpuStatsAppInfo(std::vector* outStats) const override; diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 37c6abc96b..576c72cd3c 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -27,20 +27,20 @@ namespace android { -static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded, +static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded, GpuStatsGlobalInfo* const outGlobalInfo) { switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: outGlobalInfo->glLoadingCount++; if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++; break; - case GraphicsEnv::Driver::VULKAN: - case GraphicsEnv::Driver::VULKAN_UPDATED: + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: outGlobalInfo->vkLoadingCount++; if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++; break; - case GraphicsEnv::Driver::ANGLE: + case GpuStatsInfo::Driver::ANGLE: outGlobalInfo->angleLoadingCount++; if (!isDriverLoaded) outGlobalInfo->angleLoadingFailureCount++; break; @@ -49,22 +49,22 @@ static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded, } } -static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime, +static void addLoadingTime(GpuStatsInfo::Driver driver, int64_t driverLoadingTime, GpuStatsAppInfo* const outAppInfo) { switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: if (outAppInfo->glDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime); } break; - case GraphicsEnv::Driver::VULKAN: - case GraphicsEnv::Driver::VULKAN_UPDATED: + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: if (outAppInfo->vkDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime); } break; - case GraphicsEnv::Driver::ANGLE: + case GpuStatsInfo::Driver::ANGLE: if (outAppInfo->angleDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->angleDriverLoadingTime.emplace_back(driverLoadingTime); } @@ -77,7 +77,7 @@ static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); std::lock_guard lock(mLock); diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h index b293f5988d..a79b2ba208 100644 --- a/services/gpuservice/gpustats/GpuStats.h +++ b/services/gpuservice/gpustats/GpuStats.h @@ -36,7 +36,7 @@ public: void insert(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); // Set CPU Vulkan in use signal into app stats. void setCpuVulkanInUse(const std::string& appPackageName, const uint64_t driverVersionCode); // dumpsys interface diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index d33e5528e8..680f94f42a 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -211,7 +211,7 @@ int LoadBuiltinDriver(const hwvulkan_module_t** module) { if (!ns) return -ENOENT; android::GraphicsEnv::getInstance().setDriverToLoad( - android::GraphicsEnv::Driver::VULKAN); + android::GpuStatsInfo::Driver::VULKAN); return LoadDriver(ns, module); } @@ -222,7 +222,7 @@ int LoadUpdatedDriver(const hwvulkan_module_t** module) { if (!ns) return -ENOENT; android::GraphicsEnv::getInstance().setDriverToLoad( - android::GraphicsEnv::Driver::VULKAN_UPDATED); + android::GpuStatsInfo::Driver::VULKAN_UPDATED); return LoadDriver(ns, module); } @@ -257,7 +257,7 @@ bool Hal::Open() { } if (result != 0) { android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime); ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result); return true; } @@ -271,7 +271,7 @@ bool Hal::Open() { ATRACE_END(); if (result != 0) { android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime); // Any device with a Vulkan HAL should be able to open the device. ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result), result); @@ -283,7 +283,7 @@ bool Hal::Open() { hal_.InitDebugReportIndex(); android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, true, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, true, systemTime() - openTime); return true; } -- cgit v1.2.3-59-g8ed1b From 81e26a1c64a4249bd1245c8f5f5b03fba47d225d Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 2 Jul 2019 19:48:23 -0700 Subject: GraphicsEnv: add documentations for the class Bug: 135210726 Test: build, flash and boot. Change-Id: I54f1abf0fc5d9867ee74a83d6639a767915ac738 --- libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 56 ++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index aa14059d72..d0fc580fb6 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -33,8 +33,12 @@ class GraphicsEnv { public: static GraphicsEnv& getInstance(); + // Check if device is debuggable. int getCanLoadSystemLibraries(); + /* + * Apis for updatable driver + */ // Set a search path for loading graphics drivers. The path is a list of // directories separated by ':'. A directory can be contained in a zip file // (drivers must be stored uncompressed and page aligned); such elements @@ -44,17 +48,31 @@ public: // graphics drivers. The string is a list of libraries separated by ':', // which is required by android_link_namespaces. void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries); + // Get the updatable driver namespace. android_namespace_t* getDriverNamespace(); + + /* + * Apis for GpuStats + */ + // Hint there's real activity launching on the app process. void hintActivityLaunch(); + // Set the initial GpuStats. void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); + // Set that CPU type physical device is in use. void setCpuVulkanInUse(); + // Set which driver is intended to load. void setDriverToLoad(GpuStatsInfo::Driver driver); + // Set which driver is actually loaded. void setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); - void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); + /* + * Apis for ANGLE + */ + // Check if the requested app should use ANGLE. bool shouldUseAngle(std::string appName); + // Check if this app process should use ANGLE. bool shouldUseAngle(); // Set a search path for loading ANGLE libraries. The path is a list of // directories separated by ':'. A directory can be contained in a zip file @@ -63,43 +81,75 @@ public: // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, const int rulesFd, const long rulesOffset, const long rulesLength); + // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); + // Get the app name for ANGLE debug message. std::string& getAngleAppName(); + /* + * Apis for debug layer + */ + // Set additional layer search paths. void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths); + // Get the app namespace for loading layers. NativeLoaderNamespace* getAppNamespace(); - + // Get additional layer search paths. const std::string& getLayerPaths(); - + // Set the Vulkan debug layers. void setDebugLayers(const std::string layers); + // Set the GL debug layers. void setDebugLayersGLES(const std::string layers); + // Get the debug layers to load. const std::string& getDebugLayers(); + // Get the debug layers to load. const std::string& getDebugLayersGLES(); private: enum UseAngle { UNKNOWN, YES, NO }; + // Load requested ANGLE library. void* loadLibrary(std::string name); + // Check ANGLE support with the rules. bool checkAngleRules(void* so); + // Update whether ANGLE should be used. void updateUseAngle(); + // Link updatable driver namespace with llndk and vndk-sp libs. bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace); + // Send the initial complete GpuStats to GpuService. + void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); GraphicsEnv() = default; + // Path to updatable driver libs. std::string mDriverPath; + // Path to additional sphal libs linked to updatable driver namespace. std::string mSphalLibraries; + // This mutex protects mGpuStats and get gpuservice call. std::mutex mStatsLock; + // Information bookkept for GpuStats. GpuStatsInfo mGpuStats; + // Path to ANGLE libs. std::string mAnglePath; + // This App's name. std::string mAngleAppName; + // ANGLE developer opt in status. std::string mAngleDeveloperOptIn; + // ANGLE rules. std::vector mRulesBuffer; + // Use ANGLE flag. UseAngle mUseAngle = UNKNOWN; + // Vulkan debug layers libs. std::string mDebugLayers; + // GL debug layers libs. std::string mDebugLayersGLES; + // Additional debug layers search path. std::string mLayerPaths; + // This mutex protects the namespace creation. std::mutex mNamespaceMutex; + // Updatable driver namespace. android_namespace_t* mDriverNamespace = nullptr; + // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; + // This App's namespace. NativeLoaderNamespace* mAppNamespace = nullptr; }; -- cgit v1.2.3-59-g8ed1b From bcba4117941a0506971654331d89961b6fbfd3c0 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 3 Jul 2019 13:39:32 -0700 Subject: GpuStats: refactor single stats pieces into a uniform way This change makes it easy for adding single stats pieces into GpuService without adding or modifying the binder interface each time. Bug: 135210726 Test: adb shell dumpsys gpu Change-Id: I2907065a55d03a6c1494737e6f0a77f6e94272eb --- libs/graphicsenv/GraphicsEnv.cpp | 6 +++--- libs/graphicsenv/IGpuService.cpp | 19 ++++++++++++++----- libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h | 4 ++++ libs/graphicsenv/include/graphicsenv/GraphicsEnv.h | 4 ++-- libs/graphicsenv/include/graphicsenv/IGpuService.h | 8 ++++---- services/gpuservice/GpuService.cpp | 16 +++------------- services/gpuservice/GpuService.h | 4 ++-- services/gpuservice/gpustats/GpuStats.cpp | 17 ++++++++++++++--- services/gpuservice/gpustats/GpuStats.h | 5 +++-- vulkan/libvulkan/driver.cpp | 3 ++- 10 files changed, 51 insertions(+), 35 deletions(-) (limited to 'libs') diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index a411dd56f6..c5d5f71800 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -267,14 +267,14 @@ static sp getGpuService() { return interface_cast(binder); } -void GraphicsEnv::setCpuVulkanInUse() { +void GraphicsEnv::setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value) { ATRACE_CALL(); - // Use the same stats lock to protect getGpuService() as well. std::lock_guard lock(mStatsLock); const sp gpuService = getGpuService(); if (gpuService) { - gpuService->setCpuVulkanInUse(mGpuStats.appPackageName, mGpuStats.driverVersionCode); + gpuService->setTargetStats(mGpuStats.appPackageName, mGpuStats.driverVersionCode, stats, + value); } } diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 30e5370650..9f5b0ff46f 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -92,15 +92,17 @@ public: return reply.readParcelableVector(outStats); } - virtual void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { + virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value) { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); data.writeUtf8AsUtf16(appPackageName); data.writeUint64(driverVersionCode); + data.writeInt32(static_cast(stats)); + data.writeUint64(value); - remote()->transact(BnGpuService::SET_CPU_VULKAN_IN_USE, data, &reply, IBinder::FLAG_ONEWAY); + remote()->transact(BnGpuService::SET_TARGET_STATS, data, &reply, IBinder::FLAG_ONEWAY); } }; @@ -174,7 +176,7 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep return OK; } - case SET_CPU_VULKAN_IN_USE: { + case SET_TARGET_STATS: { CHECK_INTERFACE(IGpuService, data, reply); std::string appPackageName; @@ -183,7 +185,14 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep uint64_t driverVersionCode; if ((status = data.readUint64(&driverVersionCode)) != OK) return status; - setCpuVulkanInUse(appPackageName, driverVersionCode); + int32_t stats; + if ((status = data.readInt32(&stats)) != OK) return status; + + uint64_t value; + if ((status = data.readUint64(&value)) != OK) return status; + + setTargetStats(appPackageName, driverVersionCode, + static_cast(stats), value); return OK; } diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index c2fd10ae63..711e8691ab 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -91,6 +91,10 @@ public: ANGLE = 5, }; + enum Stats { + CPU_VULKAN_IN_USE = 0, + }; + GpuStatsInfo() = default; GpuStatsInfo(const GpuStatsInfo&) = default; virtual ~GpuStatsInfo() = default; diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index d0fc580fb6..a47f468e7a 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -60,8 +60,8 @@ public: void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); - // Set that CPU type physical device is in use. - void setCpuVulkanInUse(); + // Set stats for target GpuStatsInfo::Stats type. + void setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value = 0); // Set which driver is intended to load. void setDriverToLoad(GpuStatsInfo::Driver driver); // Set which driver is actually loaded. diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index a47bbafcc4..f523d585be 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -40,9 +40,9 @@ public: const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) = 0; - // set CPU Vulkan in use signal from GraphicsEnvironment. - virtual void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) = 0; + // set target stats. + virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value = 0) = 0; // get GPU global stats from GpuStats module. virtual status_t getGpuStatsGlobalInfo(std::vector* outStats) const = 0; @@ -57,7 +57,7 @@ public: SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION, GET_GPU_STATS_GLOBAL_INFO, GET_GPU_STATS_APP_INFO, - SET_CPU_VULKAN_IN_USE, + SET_TARGET_STATS, // Always append new enum to the end. }; diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 72757dd02b..c81ab509c3 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -53,33 +53,23 @@ void GpuService::setGpuStats(const std::string& driverPackageName, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { - ATRACE_CALL(); - mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime, appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime); } status_t GpuService::getGpuStatsGlobalInfo(std::vector* outStats) const { - ATRACE_CALL(); - mGpuStats->pullGlobalStats(outStats); - return OK; } status_t GpuService::getGpuStatsAppInfo(std::vector* outStats) const { - ATRACE_CALL(); - mGpuStats->pullAppStats(outStats); - return OK; } -void GpuService::setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { - ATRACE_CALL(); - - mGpuStats->setCpuVulkanInUse(appPackageName, driverVersionCode); +void GpuService::setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value) { + mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value); } status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector& args) { diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 3e0e1b5f9b..525fb4fada 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -50,8 +50,8 @@ private: int64_t driverLoadingTime) override; status_t getGpuStatsGlobalInfo(std::vector* outStats) const override; status_t getGpuStatsAppInfo(std::vector* outStats) const override; - void setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) override; + void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value) override; /* * IBinder interface diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 576c72cd3c..423c89f797 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -126,14 +126,25 @@ void GpuStats::insert(const std::string& driverPackageName, const std::string& d addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]); } -void GpuStats::setCpuVulkanInUse(const std::string& appPackageName, - const uint64_t driverVersionCode) { +void GpuStats::insertTargetStats(const std::string& appPackageName, + const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats, + const uint64_t /*value*/) { + ATRACE_CALL(); + const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode); + + std::lock_guard lock(mLock); if (!mAppStats.count(appStatsKey)) { return; } - mAppStats[appStatsKey].cpuVulkanInUse = true; + switch (stats) { + case GpuStatsInfo::Stats::CPU_VULKAN_IN_USE: + mAppStats[appStatsKey].cpuVulkanInUse = true; + break; + default: + break; + } } void GpuStats::interceptSystemDriverStatsLocked() { diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h index a79b2ba208..656b181464 100644 --- a/services/gpuservice/gpustats/GpuStats.h +++ b/services/gpuservice/gpustats/GpuStats.h @@ -37,8 +37,9 @@ public: uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); - // Set CPU Vulkan in use signal into app stats. - void setCpuVulkanInUse(const std::string& appPackageName, const uint64_t driverVersionCode); + // Insert target stats into app stats or potentially global stats as well. + void insertTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value); // dumpsys interface void dump(const Vector& args, std::string* result); // Pull gpu global stats diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 680f94f42a..f596086ccf 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -1173,7 +1173,8 @@ VkResult CreateDevice(VkPhysicalDevice physicalDevice, if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) { // Log that the app is hitting software Vulkan implementation - android::GraphicsEnv::getInstance().setCpuVulkanInUse(); + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::CPU_VULKAN_IN_USE); } data->driver_device = dev; -- cgit v1.2.3-59-g8ed1b From 69395cd3ff5ef500c2b33991c2ab7284bc010ce9 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 3 Jul 2019 16:55:39 -0700 Subject: GpuStats: track Vulkan apps not doing pre-rotation correctly Bug: 135210726 Test: adb shell dumpsys gpu Change-Id: Iff15f0d486b74ca700c12cd960b839ddccebc112 --- libs/graphicsenv/GpuStatsInfo.cpp | 3 +++ libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h | 2 ++ services/gpuservice/gpustats/GpuStats.cpp | 3 +++ vulkan/libvulkan/swapchain.cpp | 16 ++++++++++++++++ 4 files changed, 24 insertions(+) (limited to 'libs') diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp index 4a801bec38..85137f5ca9 100644 --- a/libs/graphicsenv/GpuStatsInfo.cpp +++ b/libs/graphicsenv/GpuStatsInfo.cpp @@ -86,6 +86,7 @@ status_t GpuStatsAppInfo::writeToParcel(Parcel* parcel) const { if ((status = parcel->writeInt64Vector(vkDriverLoadingTime)) != OK) return status; if ((status = parcel->writeInt64Vector(angleDriverLoadingTime)) != OK) return status; if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status; + if ((status = parcel->writeBool(falsePrerotation)) != OK) return status; return OK; } @@ -97,6 +98,7 @@ status_t GpuStatsAppInfo::readFromParcel(const Parcel* parcel) { if ((status = parcel->readInt64Vector(&vkDriverLoadingTime)) != OK) return status; if ((status = parcel->readInt64Vector(&angleDriverLoadingTime)) != OK) return status; if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status; + if ((status = parcel->readBool(&falsePrerotation)) != OK) return status; return OK; } @@ -105,6 +107,7 @@ std::string GpuStatsAppInfo::toString() const { StringAppendF(&result, "appPackageName = %s\n", appPackageName.c_str()); StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode); StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse); + StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation); result.append("glDriverLoadingTime:"); for (int32_t loadingTime : glDriverLoadingTime) { StringAppendF(&result, " %d", loadingTime); diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index 711e8691ab..7959652189 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -70,6 +70,7 @@ public: std::vector vkDriverLoadingTime = {}; std::vector angleDriverLoadingTime = {}; bool cpuVulkanInUse = false; + bool falsePrerotation = false; }; /* @@ -93,6 +94,7 @@ public: enum Stats { CPU_VULKAN_IN_USE = 0, + FALSE_PREROTATION = 1, }; GpuStatsInfo() = default; diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 423c89f797..67babd496f 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -142,6 +142,9 @@ void GpuStats::insertTargetStats(const std::string& appPackageName, case GpuStatsInfo::Stats::CPU_VULKAN_IN_USE: mAppStats[appStatsKey].cpuVulkanInUse = true; break; + case GpuStatsInfo::Stats::FALSE_PREROTATION: + mAppStats[appStatsKey].falsePrerotation = true; + break; default: break; } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 761d128d79..e5ac2de705 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -1253,6 +1254,15 @@ VkResult CreateSwapchainKHR(VkDevice device, return VK_ERROR_SURFACE_LOST_KHR; } + int transform_hint; + err = surface.window->query(surface.window.get(), + NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); + if (err != 0) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + // -- Allocate our Swapchain object -- // After this point, we must deallocate the swapchain on error. @@ -1356,6 +1366,12 @@ VkResult CreateSwapchainKHR(VkDevice device, return result; } + if (transform_hint != swapchain->pre_transform) { + // Log that the app is not doing pre-rotation. + android::GraphicsEnv::getInstance().setTargetStats( + android::GpuStatsInfo::Stats::FALSE_PREROTATION); + } + surface.swapchain_handle = HandleFromSwapchain(swapchain); *swapchain_handle = surface.swapchain_handle; return VK_SUCCESS; -- cgit v1.2.3-59-g8ed1b From 8e09730244a3fb935d5fdae94c572bb3946c5c6e Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 8 Jul 2019 16:11:12 -0700 Subject: GpuStats: Cache the gpu service binder Cache the gpu service binder in the app process so that sending stats pieces won't try to find gpu service every time. If gpu service accidentally restarts, just ignore the later stats from the app, since the memory that holds GpuStats for that app is gone already during the gpu service restart. Test: systrace while try killing gpu service Change-Id: Ib9c38a3592f509f18d146b6c6e8f14e9e997c994 --- libs/graphicsenv/GraphicsEnv.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index a411dd56f6..1eedac111a 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -258,7 +258,7 @@ void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, } static sp getGpuService() { - const sp binder = defaultServiceManager()->checkService(String16("gpu")); + static const sp binder = defaultServiceManager()->checkService(String16("gpu")); if (!binder) { ALOGE("Failed to get gpu service"); return nullptr; -- cgit v1.2.3-59-g8ed1b From 00f511d329924824b1961e9472c3a06683fc2216 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Wed, 12 Jun 2019 16:55:40 -0700 Subject: Dispatch mouse events to window under the cursor. This CL adds cursor positions to NotifyMotionArgs, MotionEntry, InputMessage motion body and MotionEvent. Bug: 134788085 Test: The window under the cursor always responds to the gesture. Test: atest inputflinger_tests Test: atest libinput_tests Change-Id: I8ea460ed8738ffc3a5e997215685889cc1e1f2fe --- include/input/Input.h | 48 ++-- include/input/InputTransport.h | 31 +-- libs/input/Input.cpp | 55 +++-- libs/input/InputTransport.cpp | 62 ++---- libs/input/tests/InputEvent_test.cpp | 52 ++++- .../input/tests/InputPublisherAndConsumer_test.cpp | 40 ++-- libs/input/tests/StructLayout_test.cpp | 6 +- libs/input/tests/VelocityTracker_test.cpp | 13 +- services/inputflinger/InputDispatcher.cpp | 240 +++++++++++--------- services/inputflinger/InputDispatcher.h | 20 +- services/inputflinger/InputListener.cpp | 100 +++++---- services/inputflinger/InputReader.cpp | 248 +++++++++++---------- services/inputflinger/include/InputListener.h | 22 +- .../tests/InputClassifierConverter_test.cpp | 15 +- .../inputflinger/tests/InputClassifier_test.cpp | 15 +- .../inputflinger/tests/InputDispatcher_test.cpp | 143 ++++++++---- 16 files changed, 650 insertions(+), 460 deletions(-) (limited to 'libs') diff --git a/include/input/Input.h b/include/input/Input.h index 805957a5ca..a97624658c 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -24,12 +24,14 @@ */ #include +#include #include #include #include #include #include -#include + +#include /* * Additional private constants not defined in ndk/ui/input.h. @@ -246,6 +248,13 @@ enum class MotionClassification : uint8_t { */ const char* motionClassificationToString(MotionClassification classification); +/** + * Invalid value for cursor position. Used for non-mouse events, tests and injected events. Don't + * use it for direct comparison with any other value, because NaN isn't equal to itself according to + * IEEE 754. Use isnan() instead to check if a cursor position is valid. + */ +constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits::quiet_NaN(); + /* * Pointer coordinate data. */ @@ -459,6 +468,14 @@ public: inline float getYPrecision() const { return mYPrecision; } + inline float getRawXCursorPosition() const { return mXCursorPosition; } + + float getXCursorPosition() const; + + inline float getRawYCursorPosition() const { return mYCursorPosition; } + + float getYCursorPosition() const; + inline nsecs_t getDownTime() const { return mDownTime; } inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } @@ -600,26 +617,13 @@ public: ssize_t findPointerIndex(int32_t pointerId) const; - void initialize( - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); + void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, MotionClassification classification, float xOffset, + float yOffset, float xPrecision, float yPrecision, float mXCursorPosition, + float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime, + size_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); @@ -669,6 +673,8 @@ protected: float mYOffset; float mXPrecision; float mYPrecision; + float mXCursorPosition; + float mYCursorPosition; nsecs_t mDownTime; Vector mPointerProperties; Vector mSampleEventTimes; diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 63606e5911..df23f613c8 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -113,6 +113,8 @@ struct InputMessage { float yOffset; float xPrecision; float yPrecision; + float xCursorPosition; + float yCursorPosition; uint32_t pointerCount; uint32_t empty3; // Note that PointerCoords requires 8 byte alignment. @@ -261,27 +263,14 @@ public: * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. * Other errors probably indicate that the channel is broken. */ - status_t publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - uint32_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); + status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, + int32_t action, int32_t actionButton, int32_t flags, + int32_t edgeFlags, int32_t metaState, int32_t buttonState, + MotionClassification classification, float xOffset, float yOffset, + float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, + uint32_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords); /* Receives the finished signal from the consumer in reply to the original dispatch signal. * If a signal was received, returns the message sequence number, diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 9fd25f9cb7..3266b0740d 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -235,26 +235,14 @@ void PointerProperties::copyFrom(const PointerProperties& other) { // --- MotionEvent --- -void MotionEvent::initialize( - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { +void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, + int32_t metaState, int32_t buttonState, + MotionClassification classification, float xOffset, float yOffset, + float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, + size_t pointerCount, const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source, displayId); mAction = action; mActionButton = actionButton; @@ -267,6 +255,8 @@ void MotionEvent::initialize( mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; + mXCursorPosition = xCursorPosition; + mYCursorPosition = yCursorPosition; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); @@ -288,6 +278,8 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; + mXCursorPosition = other->mXCursorPosition; + mYCursorPosition = other->mYCursorPosition; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; @@ -312,6 +304,16 @@ void MotionEvent::addSample( mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); } +float MotionEvent::getXCursorPosition() const { + const float rawX = getRawXCursorPosition(); + return rawX + mXOffset; +} + +float MotionEvent::getYCursorPosition() const { + const float rawY = getRawYCursorPosition(); + return rawY + mYOffset; +} + const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; } @@ -431,6 +433,15 @@ void MotionEvent::transform(const float matrix[9]) { float originX, originY; transformPoint(matrix, 0, 0, &originX, &originY); + // Apply the transformation to cursor position. + if (!isnan(mXCursorPosition) && !isnan(mYCursorPosition)) { + float x = mXCursorPosition + oldXOffset; + float y = mYCursorPosition + oldYOffset; + transformPoint(matrix, x, y, &x, &y); + mXCursorPosition = x - mXOffset; + mYCursorPosition = y - mYOffset; + } + // Apply the transformation to all samples. size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { @@ -470,6 +481,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); + mXCursorPosition = parcel->readFloat(); + mYCursorPosition = parcel->readFloat(); mDownTime = parcel->readInt64(); mPointerProperties.clear(); @@ -521,6 +534,8 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); parcel->writeFloat(mYPrecision); + parcel->writeFloat(mXCursorPosition); + parcel->writeFloat(mYCursorPosition); parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index d02cb8ea46..904a6feb03 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -191,6 +191,10 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { msg->body.motion.xPrecision = body.motion.xPrecision; // float yPrecision msg->body.motion.yPrecision = body.motion.yPrecision; + // float xCursorPosition + msg->body.motion.xCursorPosition = body.motion.xCursorPosition; + // float yCursorPosition + msg->body.motion.yCursorPosition = body.motion.yCursorPosition; // uint32_t pointerCount msg->body.motion.pointerCount = body.motion.pointerCount; //struct Pointer pointers[MAX_POINTERS] @@ -465,26 +469,12 @@ status_t InputPublisher::publishKeyEvent( } status_t InputPublisher::publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t displayId, - int32_t action, - int32_t actionButton, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - MotionClassification classification, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - uint32_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { + uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action, + int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, MotionClassification classification, float xOffset, float yOffset, + float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, + nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { if (ATRACE_ENABLED()) { std::string message = StringPrintf( "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")", @@ -532,6 +522,8 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision; msg.body.motion.yPrecision = yPrecision; + msg.body.motion.xCursorPosition = xCursorPosition; + msg.body.motion.yCursorPosition = yCursorPosition; msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; @@ -1135,26 +1127,16 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } - event->initialize( - msg->body.motion.deviceId, - msg->body.motion.source, - msg->body.motion.displayId, - msg->body.motion.action, - msg->body.motion.actionButton, - msg->body.motion.flags, - msg->body.motion.edgeFlags, - msg->body.motion.metaState, - msg->body.motion.buttonState, - msg->body.motion.classification, - msg->body.motion.xOffset, - msg->body.motion.yOffset, - msg->body.motion.xPrecision, - msg->body.motion.yPrecision, - msg->body.motion.downTime, - msg->body.motion.eventTime, - pointerCount, - pointerProperties, - pointerCoords); + event->initialize(msg->body.motion.deviceId, msg->body.motion.source, + msg->body.motion.displayId, msg->body.motion.action, + msg->body.motion.actionButton, msg->body.motion.flags, + msg->body.motion.edgeFlags, msg->body.motion.metaState, + msg->body.motion.buttonState, msg->body.motion.classification, + msg->body.motion.xOffset, msg->body.motion.yOffset, + msg->body.motion.xPrecision, msg->body.motion.yPrecision, + msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition, + msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, + pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 2b75c82bb1..ec34f3e652 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -255,11 +255,11 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) { pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27); pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28); event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, - AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, - MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f, - ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, - 2, pointerProperties, pointerCoords); + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP, + AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE, + X_OFFSET, Y_OFFSET, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_DOWN_TIME, + ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111); @@ -571,10 +571,11 @@ TEST_F(MotionEventTest, Transform) { } MotionEvent event; event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, - 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, - AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, - 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, - 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); + 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, + 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, 0 /*yOffset*/, + 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, + 2 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount, + pointerProperties, pointerCoords); float originalRawX = 0 + 3; float originalRawY = -RADIUS + 2; @@ -602,6 +603,10 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1); } + // Check cursor positions. + ASSERT_NEAR(sinf(PI_180 * (90 + ROTATION)) * RADIUS, event.getXCursorPosition(), 0.001); + ASSERT_NEAR(-cosf(PI_180 * (90 + ROTATION)) * RADIUS, event.getYCursorPosition(), 0.001); + // Applying the transformation should preserve the raw X and Y of the first point. ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001); @@ -626,11 +631,34 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) { for (MotionClassification classification : classifications) { event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, - classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/, - pointerCount, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, + 0, classification, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(classification, event.getClassification()); } } +TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { + MotionEvent event; + constexpr size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerProperties[i].id = i; + pointerCoords[i].clear(); + } + + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, + 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, 0, + 0, 0, 0, 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/, + 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords); + event.offsetLocation(20, 60); + ASSERT_EQ(280, event.getRawXCursorPosition()); + ASSERT_EQ(540, event.getRawYCursorPosition()); + ASSERT_EQ(300, event.getXCursorPosition()); + ASSERT_EQ(600, event.getYCursorPosition()); +} + } // namespace android diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index f2cd1be33f..a362f3281d 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -146,6 +146,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr float yOffset = -20; constexpr float xPrecision = 0.25; constexpr float yPrecision = 0.5; + constexpr float xCursorPosition = 1.3; + constexpr float yCursorPosition = 50.6; constexpr nsecs_t downTime = 3; constexpr size_t pointerCount = 3; constexpr nsecs_t eventTime = 4; @@ -168,10 +170,12 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } - status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton, - flags, edgeFlags, metaState, buttonState, classification, - xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount, - pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton, + flags, edgeFlags, metaState, buttonState, classification, + xOffset, yOffset, xPrecision, yPrecision, + xCursorPosition, yCursorPosition, downTime, eventTime, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; @@ -199,6 +203,10 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { EXPECT_EQ(classification, motionEvent->getClassification()); EXPECT_EQ(xPrecision, motionEvent->getXPrecision()); EXPECT_EQ(yPrecision, motionEvent->getYPrecision()); + EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition()); + EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition()); + EXPECT_EQ(xCursorPosition + xOffset, motionEvent->getXCursorPosition()); + EXPECT_EQ(yCursorPosition + yOffset, motionEvent->getYCursorPosition()); EXPECT_EQ(downTime, motionEvent->getDownTime()); EXPECT_EQ(eventTime, motionEvent->getEventTime()); EXPECT_EQ(pointerCount, motionEvent->getPointerCount()); @@ -266,9 +274,11 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZer pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -279,9 +289,11 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; - status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } @@ -297,9 +309,11 @@ TEST_F(InputPublisherAndConsumerTest, pointerCoords[i].clear(); } - status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - MotionClassification::NONE, 0, 0, 0, 0, 0, 0, - pointerCount, pointerProperties, pointerCoords); + status = + mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE, + 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, + pointerCount, pointerProperties, pointerCoords); ASSERT_EQ(BAD_VALUE, status) << "publisher publishMotionEvent should return BAD_VALUE"; } diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index 62023fb328..8d8cf06c91 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -64,8 +64,10 @@ void TestInputMessageAlignment() { CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68); CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72); CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76); - CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80); - CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88); + CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 80); + CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 84); + CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 88); + CHECK_OFFSET(InputMessage::Body::Motion, pointers, 96); CHECK_OFFSET(InputMessage::Body::Finished, seq, 0); CHECK_OFFSET(InputMessage::Body::Finished, handled, 4); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 368446ff4d..968e2fa6bc 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -176,12 +176,13 @@ static std::vector createMotionEventStream( EXPECT_EQ(pointerIndex, pointerCount); MotionEvent event; - event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, - action, 0 /*actionButton*/, 0 /*flags*/, - AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, - MotionClassification::NONE, - 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, - 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords); + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, action, + 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, + 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, + 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, + entry.eventTime.count(), pointerCount, properties, coords); events.emplace_back(event); } diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index c2ff4c9629..b32309990f 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -262,14 +262,18 @@ static T getValueByKey(std::unordered_map& map, U key) { // --- InputDispatcher --- -InputDispatcher::InputDispatcher(const sp& policy) : - mPolicy(policy), - mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED), - mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), - mNextUnblockedEvent(nullptr), - mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - mFocusedDisplayId(ADISPLAY_ID_DEFAULT), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { +InputDispatcher::InputDispatcher(const sp& policy) + : mPolicy(policy), + mPendingEvent(nullptr), + mLastDropReason(DROP_REASON_NOT_DROPPED), + mAppSwitchSawKeyDown(false), + mAppSwitchDueTime(LONG_LONG_MAX), + mNextUnblockedEvent(nullptr), + mDispatchEnabled(false), + mDispatchFrozen(false), + mInputFilterEnabled(false), + mFocusedDisplayId(ADISPLAY_ID_DEFAULT), + mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mReporter = createInputReporter(); @@ -1326,6 +1330,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction); + const bool isFromMouse = entry->source == AINPUT_SOURCE_MOUSE; bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; @@ -1361,11 +1366,17 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ + int32_t x; + int32_t y; int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); + // Always dispatch mouse events to cursor position. + if (isFromMouse) { + x = int32_t(entry->xCursorPosition); + y = int32_t(entry->yCursorPosition); + } else { + x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X)); + y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)); + } bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN; sp newTouchedWindowHandle = findTouchedWindowAtLocked( displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/); @@ -2256,15 +2267,21 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } // Publish the motion event. - status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, - motionEntry->deviceId, motionEntry->source, motionEntry->displayId, - dispatchEntry->resolvedAction, motionEntry->actionButton, - dispatchEntry->resolvedFlags, motionEntry->edgeFlags, - motionEntry->metaState, motionEntry->buttonState, motionEntry->classification, - xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->downTime, motionEntry->eventTime, - motionEntry->pointerCount, motionEntry->pointerProperties, - usingCoords); + status = + connection->inputPublisher + .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, + motionEntry->source, motionEntry->displayId, + dispatchEntry->resolvedAction, + motionEntry->actionButton, + dispatchEntry->resolvedFlags, + motionEntry->edgeFlags, motionEntry->metaState, + motionEntry->buttonState, + motionEntry->classification, xOffset, yOffset, + motionEntry->xPrecision, motionEntry->yPrecision, + motionEntry->xCursorPosition, + motionEntry->yCursorPosition, motionEntry->downTime, + motionEntry->eventTime, motionEntry->pointerCount, + motionEntry->pointerProperties, usingCoords); break; } @@ -2590,24 +2607,17 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet } } - MotionEntry* splitMotionEntry = new MotionEntry( - originalMotionEntry->sequenceNum, - originalMotionEntry->eventTime, - originalMotionEntry->deviceId, - originalMotionEntry->source, - originalMotionEntry->displayId, - originalMotionEntry->policyFlags, - action, - originalMotionEntry->actionButton, - originalMotionEntry->flags, - originalMotionEntry->metaState, - originalMotionEntry->buttonState, - originalMotionEntry->classification, - originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, - originalMotionEntry->yPrecision, - originalMotionEntry->downTime, - splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); + MotionEntry* splitMotionEntry = + new MotionEntry(originalMotionEntry->sequenceNum, originalMotionEntry->eventTime, + originalMotionEntry->deviceId, originalMotionEntry->source, + originalMotionEntry->displayId, originalMotionEntry->policyFlags, + action, originalMotionEntry->actionButton, originalMotionEntry->flags, + originalMotionEntry->metaState, originalMotionEntry->buttonState, + originalMotionEntry->classification, originalMotionEntry->edgeFlags, + originalMotionEntry->xPrecision, originalMotionEntry->yPrecision, + originalMotionEntry->xCursorPosition, + originalMotionEntry->yCursorPosition, originalMotionEntry->downTime, + splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0); if (originalMotionEntry->injectionState) { splitMotionEntry->injectionState = originalMotionEntry->injectionState; @@ -2753,12 +2763,14 @@ bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 - ", policyFlags=0x%x, " - "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x," - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64, - args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, - args->action, args->actionButton, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); + ", policyFlags=0x%x, " + "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, " + "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, " + "mYCursorPosition=%f, downTime=%" PRId64, + args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, + args->action, args->actionButton, args->flags, args->metaState, args->buttonState, + args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition, + args->yCursorPosition, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " @@ -2800,12 +2812,12 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { mLock.unlock(); MotionEvent event; - event.initialize(args->deviceId, args->source, args->displayId, - args->action, args->actionButton, - args->flags, args->edgeFlags, args->metaState, args->buttonState, - args->classification, 0, 0, args->xPrecision, args->yPrecision, - args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); + event.initialize(args->deviceId, args->source, args->displayId, args->action, + args->actionButton, args->flags, args->edgeFlags, args->metaState, + args->buttonState, args->classification, 0, 0, args->xPrecision, + args->yPrecision, args->xCursorPosition, args->yCursorPosition, + args->downTime, args->eventTime, args->pointerCount, + args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -2816,12 +2828,14 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { } // Just enqueue a new motion event. - MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime, - args->deviceId, args->source, args->displayId, policyFlags, - args->action, args->actionButton, args->flags, - args->metaState, args->buttonState, args->classification, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, - args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0); + MotionEntry* newEntry = + new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source, + args->displayId, policyFlags, args->action, args->actionButton, + args->flags, args->metaState, args->buttonState, + args->classification, args->edgeFlags, args->xPrecision, + args->yPrecision, args->xCursorPosition, args->yCursorPosition, + args->downTime, args->pointerCount, args->pointerProperties, + args->pointerCoords, 0, 0); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); @@ -2952,31 +2966,34 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - firstInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(), - policyFlags, - action, actionButton, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getClassification(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); + firstInjectedEntry = + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, action, actionButton, + motionEvent->getFlags(), motionEvent->getMetaState(), + motionEvent->getButtonState(), motionEvent->getClassification(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), + motionEvent->getYPrecision(), motionEvent->getRawXCursorPosition(), + motionEvent->getRawYCursorPosition(), motionEvent->getDownTime(), + uint32_t(pointerCount), pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry = firstInjectedEntry; for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { sampleEventTimes += 1; samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, - *sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), - motionEvent->getDisplayId(), policyFlags, - action, actionButton, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getClassification(), motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), - uint32_t(pointerCount), pointerProperties, samplePointerCoords, - motionEvent->getXOffset(), motionEvent->getYOffset()); + MotionEntry* nextInjectedEntry = + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes, + motionEvent->getDeviceId(), motionEvent->getSource(), + motionEvent->getDisplayId(), policyFlags, action, actionButton, + motionEvent->getFlags(), motionEvent->getMetaState(), + motionEvent->getButtonState(), motionEvent->getClassification(), + motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), + motionEvent->getYPrecision(), + motionEvent->getRawXCursorPosition(), + motionEvent->getRawYCursorPosition(), + motionEvent->getDownTime(), uint32_t(pointerCount), + pointerProperties, samplePointerCoords, + motionEvent->getXOffset(), motionEvent->getYOffset()); lastInjectedEntry->next = nextInjectedEntry; lastInjectedEntry = nextInjectedEntry; } @@ -4633,21 +4650,32 @@ void InputDispatcher::KeyEntry::recycle() { // --- InputDispatcher::MotionEntry --- -InputDispatcher::MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, - uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, - int32_t actionButton, +InputDispatcher::MotionEntry::MotionEntry( + uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, - uint32_t pointerCount, + int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset) : - EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags), + float xOffset, float yOffset) + : EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags), eventTime(eventTime), - deviceId(deviceId), source(source), displayId(displayId), action(action), - actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState), - classification(classification), edgeFlags(edgeFlags), - xPrecision(xPrecision), yPrecision(yPrecision), - downTime(downTime), pointerCount(pointerCount) { + deviceId(deviceId), + source(source), + displayId(displayId), + action(action), + actionButton(actionButton), + flags(flags), + metaState(metaState), + buttonState(buttonState), + classification(classification), + edgeFlags(edgeFlags), + xPrecision(xPrecision), + yPrecision(yPrecision), + xCursorPosition(xCursorPosition), + yCursorPosition(yCursorPosition), + downTime(downTime), + pointerCount(pointerCount) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); @@ -4662,11 +4690,14 @@ InputDispatcher::MotionEntry::~MotionEntry() { void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const { msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 - ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, " - "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[", - deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags, - metaState, buttonState, motionClassificationToString(classification), edgeFlags, - xPrecision, yPrecision); + ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, " + "buttonState=0x%08x, " + "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " + "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[", + deviceId, source, displayId, motionActionToString(action).c_str(), + actionButton, flags, metaState, buttonState, + motionClassificationToString(classification), edgeFlags, xPrecision, + yPrecision, xCursorPosition, yCursorPosition); for (uint32_t i = 0; i < pointerCount; i++) { if (i) { @@ -4936,6 +4967,8 @@ void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, memento.flags = flags; memento.xPrecision = entry->xPrecision; memento.yPrecision = entry->yPrecision; + memento.xCursorPosition = entry->xCursorPosition; + memento.yCursorPosition = entry->yCursorPosition; memento.downTime = entry->downTime; memento.setPointers(entry); memento.hovering = hovering; @@ -4966,13 +4999,16 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim if (shouldCancelMotion(memento, options)) { const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; - outEvents.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, - memento.deviceId, memento.source, memento.displayId, memento.policyFlags, - action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - memento.xPrecision, memento.yPrecision, memento.downTime, - memento.pointerCount, memento.pointerProperties, memento.pointerCoords, - 0 /*xOffset*/, 0 /*yOffset*/)); + outEvents.push_back( + new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, memento.deviceId, + memento.source, memento.displayId, memento.policyFlags, action, + 0 /*actionButton*/, memento.flags, AMETA_NONE, + 0 /*buttonState*/, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, + memento.yPrecision, memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, memento.pointerCount, + memento.pointerProperties, memento.pointerCoords, 0 /*xOffset*/, + 0 /*yOffset*/)); } } } diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h index 753b748884..46dd9bd273 100644 --- a/services/inputflinger/InputDispatcher.h +++ b/services/inputflinger/InputDispatcher.h @@ -570,19 +570,21 @@ private: int32_t edgeFlags; float xPrecision; float yPrecision; + float xCursorPosition; + float yCursorPosition; nsecs_t downTime; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; - MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, - int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t actionButton, int32_t flags, - int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xOffset, float yOffset); + MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, + MotionClassification classification, int32_t edgeFlags, float xPrecision, + float yPrecision, float xCursorPosition, float yCursorPosition, + nsecs_t downTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xOffset, float yOffset); virtual void appendDescription(std::string& msg) const; protected: @@ -830,6 +832,8 @@ private: int32_t flags; float xPrecision; float yPrecision; + float xCursorPosition; + float yCursorPosition; nsecs_t downTime; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index 423b69cff3..0498e87732 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -21,6 +21,7 @@ #include "InputListener.h" #include +#include namespace android { @@ -87,21 +88,33 @@ void NotifyKeyArgs::notify(const sp& listener) const { // --- NotifyMotionArgs --- -NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, - uint32_t source, int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, - int32_t buttonState, MotionClassification classification, +NotifyMotionArgs::NotifyMotionArgs( + uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime, - const std::vector& videoFrames) : - NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source), - displayId(displayId), policyFlags(policyFlags), - action(action), actionButton(actionButton), - flags(flags), metaState(metaState), buttonState(buttonState), - classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp), + float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, + nsecs_t downTime, const std::vector& videoFrames) + : NotifyArgs(sequenceNum, eventTime), + deviceId(deviceId), + source(source), + displayId(displayId), + policyFlags(policyFlags), + action(action), + actionButton(actionButton), + flags(flags), + metaState(metaState), + buttonState(buttonState), + classification(classification), + edgeFlags(edgeFlags), + deviceTimestamp(deviceTimestamp), pointerCount(pointerCount), - xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime), + xPrecision(xPrecision), + yPrecision(yPrecision), + xCursorPosition(xCursorPosition), + yCursorPosition(yCursorPosition), + downTime(downTime), videoFrames(videoFrames) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); @@ -109,14 +122,26 @@ NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int3 } } -NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : - NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId), - source(other.source), displayId(other.displayId), policyFlags(other.policyFlags), - action(other.action), actionButton(other.actionButton), flags(other.flags), - metaState(other.metaState), buttonState(other.buttonState), - classification(other.classification), edgeFlags(other.edgeFlags), - deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount), - xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime), +NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) + : NotifyArgs(other.sequenceNum, other.eventTime), + deviceId(other.deviceId), + source(other.source), + displayId(other.displayId), + policyFlags(other.policyFlags), + action(other.action), + actionButton(other.actionButton), + flags(other.flags), + metaState(other.metaState), + buttonState(other.buttonState), + classification(other.classification), + edgeFlags(other.edgeFlags), + deviceTimestamp(other.deviceTimestamp), + pointerCount(other.pointerCount), + xPrecision(other.xPrecision), + yPrecision(other.yPrecision), + xCursorPosition(other.xCursorPosition), + yCursorPosition(other.yCursorPosition), + downTime(other.downTime), videoFrames(other.videoFrames) { for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); @@ -124,28 +149,23 @@ NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : } } +static inline bool isCursorPositionEqual(float lhs, float rhs) { + return (isnan(lhs) && isnan(rhs)) || lhs == rhs; +} + bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const { - bool equal = - sequenceNum == rhs.sequenceNum - && eventTime == rhs.eventTime - && deviceId == rhs.deviceId - && source == rhs.source - && displayId == rhs.displayId - && policyFlags == rhs.policyFlags - && action == rhs.action - && actionButton == rhs.actionButton - && flags == rhs.flags - && metaState == rhs.metaState - && buttonState == rhs.buttonState - && classification == rhs.classification - && edgeFlags == rhs.edgeFlags - && deviceTimestamp == rhs.deviceTimestamp - && pointerCount == rhs.pointerCount + bool equal = sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime && + deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId && + policyFlags == rhs.policyFlags && action == rhs.action && + actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState && + buttonState == rhs.buttonState && classification == rhs.classification && + edgeFlags == rhs.edgeFlags && deviceTimestamp == rhs.deviceTimestamp && + pointerCount == rhs.pointerCount // PointerProperties and PointerCoords are compared separately below - && xPrecision == rhs.xPrecision - && yPrecision == rhs.yPrecision - && downTime == rhs.downTime - && videoFrames == rhs.videoFrames; + && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision && + isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) && + isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) && + downTime == rhs.downTime && videoFrames == rhs.videoFrames; if (!equal) { return false; } diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index a45b8a56ce..9e5990964c 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -2782,6 +2782,8 @@ void CursorInputMapper::sync(nsecs_t when) { mPointerVelocityControl.move(when, &deltaX, &deltaY); int32_t displayId; + float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; + float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; if (mSource == AINPUT_SOURCE_MOUSE) { if (moved || scrolled || buttonsChanged) { mPointerController->setPresentation( @@ -2798,10 +2800,9 @@ void CursorInputMapper::sync(nsecs_t when) { mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } - float x, y; - mPointerController->getPosition(&x, &y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); displayId = mPointerController->getDisplayId(); @@ -2845,21 +2846,25 @@ void CursorInputMapper::sync(nsecs_t when) { int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); buttonState &= ~actionButton; NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, - metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, + xCursorPosition, yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&releaseArgs); } } NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, - displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + displayId, policyFlags, motionEventAction, 0, 0, metaState, + currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&args); if (buttonsPressed) { @@ -2868,11 +2873,14 @@ void CursorInputMapper::sync(nsecs_t when) { int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); buttonState |= actionButton; NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS, - actionButton, 0, metaState, buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, + xCursorPosition, yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&pressArgs); } } @@ -2882,12 +2890,14 @@ void CursorInputMapper::sync(nsecs_t when) { // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { - NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, + 0, metaState, currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, + yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&hoverArgs); } @@ -2897,11 +2907,14 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime, /* videoFrames */ {}); + mSource, displayId, policyFlags, + AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, + currentButtonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, + &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, + yCursorPosition, downTime, + /* videoFrames */ {}); getListener()->notifyMotion(&scrollArgs); } } @@ -3041,12 +3054,13 @@ void RotaryEncoderInputMapper::sync(nsecs_t when) { int32_t metaState = mContext->getGlobalMetaState(); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); - NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, 0, /* videoFrames */ {}); + NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, + metaState, /* buttonState */ 0, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, + 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); getListener()->notifyMotion(&scrollArgs); } @@ -5450,12 +5464,12 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); const int32_t displayId = mPointerController->getDisplayId(); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, - metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, - 0, 0, mPointerGesture.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, + x, y, mPointerGesture.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6360,29 +6374,31 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, int32_t metaState = getContext()->getGlobalMetaState(); int32_t displayId = mViewport.displayId; - if (mPointerController != nullptr) { - if (down || hovering) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentRawState.buttonState); - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } - displayId = mPointerController->getDisplayId(); + if (down || hovering) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); + mPointerController->clearSpots(); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); + } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } + displayId = mPointerController->getDisplayId(); + + float xCursorPosition; + float yCursorPosition; + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); if (mPointerSimple.down && !down) { mPointerSimple.down = false; // Send up. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState, + mLastRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6390,13 +6406,13 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = false; // Send hover exit. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, + metaState, mLastRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6406,25 +6422,25 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.downTime = when; // Send down. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, - /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0, + metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, xCursorPosition, yCursorPosition, + mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } // Send move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6433,26 +6449,25 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, mPointerSimple.hovering = true; // Send hover enter. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, + metaState, mCurrentRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties, + &mPointerSimple.currentCoords, mOrientedXPrecision, + mOrientedYPrecision, xCursorPosition, yCursorPosition, + mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } // Send hover move. - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, - mCurrentRawState.buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, + metaState, mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6468,13 +6483,13 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - mSource, displayId, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, - 1, &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime, /* videoFrames */ {}); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, + displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, + mCurrentRawState.buttonState, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + &mPointerSimple.currentProperties, &pointerCoords, + mOrientedXPrecision, mOrientedYPrecision, xCursorPosition, + yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {}); getListener()->notifyMotion(&args); } @@ -6531,16 +6546,21 @@ void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32 ALOG_ASSERT(false); } } + float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; + float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; + if (mDeviceMode == DEVICE_MODE_POINTER) { + mPointerController->getPosition(&xCursorPosition, &yCursorPosition); + } const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE); const int32_t deviceId = getDeviceId(); std::vector frames = mDevice->getEventHub()->getVideoFrames(deviceId); std::for_each(frames.begin(), frames.end(), [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); }); - NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, - source, displayId, policyFlags, - action, actionButton, flags, metaState, buttonState, MotionClassification::NONE, - edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords, - xPrecision, yPrecision, downTime, std::move(frames)); + NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId, + policyFlags, action, actionButton, flags, metaState, buttonState, + MotionClassification::NONE, edgeFlags, deviceTimestamp, pointerCount, + pointerProperties, pointerCoords, xPrecision, yPrecision, xCursorPosition, + yCursorPosition, downTime, std::move(frames)); getListener()->notifyMotion(&args); } @@ -7462,10 +7482,12 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { uint32_t policyFlags = 0; NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), - AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, - &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {}); + AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags, + AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, + /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); getListener()->notifyMotion(&args); } diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h index b51dcb6cad..57c894bf8b 100644 --- a/services/inputflinger/include/InputListener.h +++ b/services/inputflinger/include/InputListener.h @@ -119,19 +119,27 @@ struct NotifyMotionArgs : public NotifyArgs { PointerCoords pointerCoords[MAX_POINTERS]; float xPrecision; float yPrecision; + /** + * Mouse cursor position when this event is reported relative to the origin of the specified + * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in + * gestures enabled mode. + */ + float xCursorPosition; + float yCursorPosition; nsecs_t downTime; std::vector videoFrames; inline NotifyMotionArgs() { } NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source, - int32_t displayId, uint32_t policyFlags, - int32_t action, int32_t actionButton, int32_t flags, - int32_t metaState, int32_t buttonState, MotionClassification classification, - int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime, - const std::vector& videoFrames); + int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, + int32_t flags, int32_t metaState, int32_t buttonState, + MotionClassification classification, int32_t edgeFlags, + uint32_t deviceTimestamp, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, + float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, nsecs_t downTime, + const std::vector& videoFrames); NotifyMotionArgs(const NotifyMotionArgs& other); diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp index 813b69edbb..ba1c7c9284 100644 --- a/services/inputflinger/tests/InputClassifierConverter_test.cpp +++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp @@ -38,12 +38,15 @@ static NotifyMotionArgs generateBasicMotionArgs() { coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 2); coords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.5); static constexpr nsecs_t downTime = 2; - NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/, - AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN, - 0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/, - 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/, - downTime, {}/*videoFrames*/); + NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/, + AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/, + AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/, + AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/, + 1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/, + 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, + {} /*videoFrames*/); return motionArgs; } diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index 7cc17a2215..9bc4282d9c 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -38,12 +38,15 @@ static NotifyMotionArgs generateBasicMotionArgs() { coords.setAxisValue(AMOTION_EVENT_AXIS_X, 1); coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1); static constexpr nsecs_t downTime = 2; - NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/, - AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN, - 0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/, - 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/, - downTime, {}/*videoFrames*/); + NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/, + AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/, + AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/, + AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/, + 1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/, + 0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, + {} /*videoFrames*/); return motionArgs; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 9fe6481ca0..c28a6214d6 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -249,8 +249,10 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects undefined motion actions. event.initialize(DEVICE_ID, source, DISPLAY_ID, - /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -258,18 +260,24 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer down with invalid index. event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_DOWN | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer down index too large."; event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_DOWN | + (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -277,36 +285,45 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects pointer up with invalid index. event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_UP | + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too large."; event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + AMOTION_EVENT_ACTION_POINTER_UP | + (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer up index too small."; // Rejects motion events with invalid number of pointers. - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 0, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with 0 pointers."; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -314,18 +331,22 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with invalid pointer ids. pointerProperties[0].id = -1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) << "Should reject motion events with pointer ids less than 0."; pointerProperties[0].id = MAX_POINTER_ID + 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 1, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -334,9 +355,11 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { // Rejects motion events with duplicate pointer ids. pointerProperties[0].id = 1; pointerProperties[1].id = 1; - event.initialize(DEVICE_ID, source, DISPLAY_ID, - AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0, - ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); + event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, + metaState, 0, classification, 0, 0, 0, 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, + ARBITRARY_TIME, ARBITRARY_TIME, + /*pointerCount*/ 2, pointerProperties, pointerCoords); ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( &event, INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) @@ -463,6 +486,7 @@ public: mInfo.frameRight = mFrame.right; mInfo.frameBottom = mFrame.bottom; mInfo.globalScaleFactor = 1.0; + mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); mInfo.visible = true; mInfo.canReceiveKeys = true; @@ -521,8 +545,10 @@ static int32_t injectKeyDown(const sp& dispatcher, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); } -static int32_t injectMotionDown(const sp& dispatcher, int32_t source, - int32_t displayId, int32_t x = 100, int32_t y = 200) { +static int32_t injectMotionEvent(const sp& dispatcher, int32_t action, + int32_t source, int32_t displayId, int32_t x, int32_t y, + int32_t xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION, + int32_t yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION) { MotionEvent event; PointerProperties pointerProperties[1]; PointerCoords pointerCoords[1]; @@ -537,12 +563,11 @@ static int32_t injectMotionDown(const sp& dispatcher, int32_t s nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. - event.initialize(DEVICE_ID, source, displayId, - AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, - AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, - /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, - /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties, - pointerCoords); + event.initialize(DEVICE_ID, source, displayId, action, /* actionButton */ 0, /* flags */ 0, + /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, + /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, + /* yPrecision */ 0, xCursorPosition, yCursorPosition, currentTime, currentTime, + /*pointerCount*/ 1, pointerProperties, pointerCoords); // Inject event until dispatch out. return dispatcher->injectInputEvent( @@ -551,6 +576,11 @@ static int32_t injectMotionDown(const sp& dispatcher, int32_t s INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); } +static int32_t injectMotionDown(const sp& dispatcher, int32_t source, + int32_t displayId, int32_t x = 100, int32_t y = 200) { + return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y); +} + static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. @@ -576,11 +606,12 @@ static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32 nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion event. NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId, - POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0, - AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, pointerProperties, - pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, currentTime, - /* videoFrames */ {}); + POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0, + AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, + pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {}); return args; } @@ -704,6 +735,32 @@ TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) { windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE); } +TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { + sp application = new FakeApplicationHandle(); + + sp windowLeft = + new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + windowLeft->setFrame(Rect(0, 0, 600, 800)); + windowLeft->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + sp windowRight = + new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + windowRight->setFrame(Rect(600, 0, 1200, 800)); + windowRight->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + std::vector> inputWindowHandles{windowLeft, windowRight}; + mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); + + // Inject an event with coordinate in the area of right window, with mouse cursor in the area of + // left window. This event should be dispatched to the left window. + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE, + ADISPLAY_ID_DEFAULT, 610, 400, 599, 400)); + windowLeft->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT); + windowRight->assertNoEvents(); +} + /* Test InputDispatcher for MultiDisplay */ class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest { public: -- cgit v1.2.3-59-g8ed1b From efb71afcbb5d8f57af6435391f5d4835696375cc Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 27 Jun 2019 14:45:53 -0700 Subject: blast: fix registering callbacks This is a better fix for b/134194071 than ag/7998544. The previous patch only protected the call to notify the binder thread to send a callback. This patch has both a start registration and end registration call. During that time, the transaction callback cannot be sent. This is closer to a long term fix for the bug. Bug: 134194071 Test: Switch between front and back cameras to make sure the app doesn't crash. Change-Id: I2d20c13cc1c8d13e5a1340dfaa8cbbaa4d3a30ab --- .../include/gui/ITransactionCompletedListener.h | 10 +++++ services/surfaceflinger/BufferStateLayer.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 19 ++++---- .../surfaceflinger/TransactionCompletedThread.cpp | 50 ++++++++++++++++++--- .../surfaceflinger/TransactionCompletedThread.h | 51 ++++++++++++++++------ 5 files changed, 102 insertions(+), 32 deletions(-) (limited to 'libs') diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 774ad46b15..cbfd365692 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -106,6 +106,16 @@ public: const std::vector& ids) : transactionCompletedListener(listener), callbackIds(ids) {} + bool operator==(const ListenerCallbacks& rhs) const { + if (transactionCompletedListener != rhs.transactionCompletedListener) { + return false; + } + if (callbackIds.empty()) { + return rhs.callbackIds.empty(); + } + return callbackIds.front() == rhs.callbackIds.front(); + } + sp transactionCompletedListener; std::vector callbackIds; }; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 2abc1a75a9..4b01301467 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -85,7 +85,7 @@ void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const { } void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { - mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles( + mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles( mDrawingState.callbackHandles); mDrawingState.callbackHandles = {}; @@ -310,7 +310,7 @@ bool BufferStateLayer::setTransactionCompletedListeners( } else { // If this layer will NOT need to be relatched and presented this frame // Notify the transaction completed thread this handle is done - mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle); + mFlinger->getTransactionCompletedThread().registerUnpresentedCallbackHandle(handle); } } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f53d3faef8..7d8630f6b1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2183,14 +2183,7 @@ void SurfaceFlinger::postComposition() } mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]); - - // Lock the mStateLock in case SurfaceFlinger is in the middle of applying a transaction. - // If we do not lock here, a callback could be sent without all of its SurfaceControls and - // metrics. - { - Mutex::Autolock _l(mStateLock); - mTransactionCompletedThread.sendCallbacks(); - } + mTransactionCompletedThread.sendCallbacks(); if (mLumaSampling && mRegionSamplingThread) { mRegionSamplingThread->notifyNewContent(); @@ -3790,8 +3783,8 @@ void SurfaceFlinger::applyTransactionState(const Vector& states, if (!listenerCallbacks.empty()) { mTransactionCompletedThread.run(); } - for (const auto& [listener, callbackIds] : listenerCallbacks) { - mTransactionCompletedThread.addCallback(listener, callbackIds); + for (const auto& listenerCallback : listenerCallbacks) { + mTransactionCompletedThread.startRegistration(listenerCallback); } uint32_t clientStateFlags = 0; @@ -3800,6 +3793,10 @@ void SurfaceFlinger::applyTransactionState(const Vector& states, postTime, privileged); } + for (const auto& listenerCallback : listenerCallbacks) { + mTransactionCompletedThread.endRegistration(listenerCallback); + } + // If the state doesn't require a traversal and there are callbacks, send them now if (!(clientStateFlags & eTraversalNeeded) && !listenerCallbacks.empty()) { mTransactionCompletedThread.sendCallbacks(); @@ -3937,7 +3934,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( sp layer(client->getLayerUser(s.surface)); if (layer == nullptr) { for (auto& listenerCallback : listenerCallbacks) { - mTransactionCompletedThread.addUnpresentedCallbackHandle( + mTransactionCompletedThread.registerUnpresentedCallbackHandle( new CallbackHandle(listenerCallback.transactionCompletedListener, listenerCallback.callbackIds, s.surface)); } diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp index 5cf8eb1a1d..0806f2aa93 100644 --- a/services/surfaceflinger/TransactionCompletedThread.cpp +++ b/services/surfaceflinger/TransactionCompletedThread.cpp @@ -75,14 +75,15 @@ void TransactionCompletedThread::run() { mThread = std::thread(&TransactionCompletedThread::threadMain, this); } -status_t TransactionCompletedThread::addCallback(const sp& listener, - const std::vector& callbackIds) { +status_t TransactionCompletedThread::startRegistration(const ListenerCallbacks& listenerCallbacks) { std::lock_guard lock(mMutex); if (!mRunning) { ALOGE("cannot add callback because the callback thread isn't running"); return BAD_VALUE; } + auto& [listener, callbackIds] = listenerCallbacks; + if (mCompletedTransactions.count(listener) == 0) { status_t err = IInterface::asBinder(listener)->linkToDeath(mDeathRecipient); if (err != NO_ERROR) { @@ -91,11 +92,41 @@ status_t TransactionCompletedThread::addCallback(const sp& transactionListener, + const std::vector& callbackIds) { + ListenerCallbacks listenerCallbacks(transactionListener, callbackIds); + + auto itr = mRegisteringTransactions.find(listenerCallbacks); + return itr != mRegisteringTransactions.end(); +} + status_t TransactionCompletedThread::registerPendingCallbackHandle( const sp& handle) { std::lock_guard lock(mMutex); @@ -105,7 +136,7 @@ status_t TransactionCompletedThread::registerPendingCallbackHandle( } // If we can't find the transaction stats something has gone wrong. The client should call - // addCallback before trying to register a pending callback handle. + // startRegistration before trying to register a pending callback handle. TransactionStats* transactionStats; status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats); if (err != NO_ERROR) { @@ -117,7 +148,7 @@ status_t TransactionCompletedThread::registerPendingCallbackHandle( return NO_ERROR; } -status_t TransactionCompletedThread::addPresentedCallbackHandles( +status_t TransactionCompletedThread::finalizePendingCallbackHandles( const std::deque>& handles) { std::lock_guard lock(mMutex); if (!mRunning) { @@ -158,7 +189,7 @@ status_t TransactionCompletedThread::addPresentedCallbackHandles( return NO_ERROR; } -status_t TransactionCompletedThread::addUnpresentedCallbackHandle( +status_t TransactionCompletedThread::registerUnpresentedCallbackHandle( const sp& handle) { std::lock_guard lock(mMutex); if (!mRunning) { @@ -189,7 +220,7 @@ status_t TransactionCompletedThread::findTransactionStats( status_t TransactionCompletedThread::addCallbackHandle(const sp& handle) { // If we can't find the transaction stats something has gone wrong. The client should call - // addCallback before trying to add a presnted callback handle. + // startRegistration before trying to add a callback handle. TransactionStats* transactionStats; status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats); if (err != NO_ERROR) { @@ -233,6 +264,13 @@ void TransactionCompletedThread::threadMain() { while (transactionStatsItr != transactionStatsDeque.end()) { auto& transactionStats = *transactionStatsItr; + // If this transaction is still registering, it is not safe to send a callback + // because there could be surface controls that haven't been added to + // transaction stats or mPendingTransactions. + if (isRegisteringTransaction(listener, transactionStats.callbackIds)) { + break; + } + // If we are still waiting on the callback handles for this transaction, stop // here because all transaction callbacks for the same listener must come in order auto pendingTransactions = mPendingTransactions.find(listener); diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h index 21e2678701..b821350657 100644 --- a/services/surfaceflinger/TransactionCompletedThread.h +++ b/services/surfaceflinger/TransactionCompletedThread.h @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -30,6 +31,12 @@ namespace android { +struct ITransactionCompletedListenerHash { + std::size_t operator()(const sp& listener) const { + return std::hash{}((listener) ? IInterface::asBinder(listener).get() : nullptr); + } +}; + struct CallbackIdsHash { // CallbackId vectors have several properties that let us get away with this simple hash. // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is @@ -42,6 +49,22 @@ struct CallbackIdsHash { } }; +struct ListenerCallbacksHash { + std::size_t HashCombine(size_t value1, size_t value2) const { + return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); + } + + std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { + struct ITransactionCompletedListenerHash listenerHasher; + struct CallbackIdsHash callbackIdsHasher; + + std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); + std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); + + return HashCombine(listenerHash, callbackIdsHash); + } +}; + class CallbackHandle : public RefBase { public: CallbackHandle(const sp& transactionListener, @@ -64,10 +87,12 @@ public: void run(); // Adds listener and callbackIds in case there are no SurfaceControls that are supposed - // to be included in the callback. This functions should be call before attempting to add any - // callback handles. - status_t addCallback(const sp& transactionListener, - const std::vector& callbackIds); + // to be included in the callback. This functions should be call before attempting to register + // any callback handles. + status_t startRegistration(const ListenerCallbacks& listenerCallbacks); + // Ends the registration. After this is called, no more CallbackHandles will be registered. + // It is safe to send a callback if the Transaction doesn't have any Pending callback handles. + status_t endRegistration(const ListenerCallbacks& listenerCallbacks); // Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle // that needs to be latched and presented this frame. This function should be called once the @@ -76,11 +101,11 @@ public: // presented. status_t registerPendingCallbackHandle(const sp& handle); // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented. - status_t addPresentedCallbackHandles(const std::deque>& handles); + status_t finalizePendingCallbackHandles(const std::deque>& handles); // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and // presented this frame. - status_t addUnpresentedCallbackHandle(const sp& handle); + status_t registerUnpresentedCallbackHandle(const sp& handle); void addPresentFence(const sp& presentFence); @@ -89,6 +114,9 @@ public: private: void threadMain(); + bool isRegisteringTransaction(const sp& transactionListener, + const std::vector& callbackIds) REQUIRES(mMutex); + status_t findTransactionStats(const sp& listener, const std::vector& callbackIds, TransactionStats** outTransactionStats) REQUIRES(mMutex); @@ -106,13 +134,6 @@ private: }; sp mDeathRecipient; - struct ITransactionCompletedListenerHash { - std::size_t operator()(const sp& listener) const { - return std::hash{}((listener) ? IInterface::asBinder(listener).get() - : nullptr); - } - }; - // Protects the creation and destruction of mThread std::mutex mThreadMutex; @@ -121,11 +142,15 @@ private: std::mutex mMutex; std::condition_variable_any mConditionVariable; + std::unordered_set mRegisteringTransactions + GUARDED_BY(mMutex); + std::unordered_map< sp, std::unordered_map, uint32_t /*count*/, CallbackIdsHash>, ITransactionCompletedListenerHash> mPendingTransactions GUARDED_BY(mMutex); + std::unordered_map, std::deque, ITransactionCompletedListenerHash> mCompletedTransactions GUARDED_BY(mMutex); -- cgit v1.2.3-59-g8ed1b From ab0ab9c57c8fa9d8c9648734fea74ee010e28e8c Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Wed, 10 Jul 2019 18:58:28 -0700 Subject: Address comments from a previous change. The original change is 00f511d329924824b1961e9472c3a06683fc2216. Bug: 134788085 Test: atest libinput_tests Change-Id: I1f3326067f94fe6a09850f4389483e60fa57a8d4 --- include/input/Input.h | 3 +++ libs/input/Input.cpp | 3 +-- libs/input/tests/InputEvent_test.cpp | 10 +++++++--- services/inputflinger/InputDispatcher.cpp | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) (limited to 'libs') diff --git a/include/input/Input.h b/include/input/Input.h index a97624658c..ad8c233577 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -476,6 +477,8 @@ public: float getYCursorPosition() const; + static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } + inline nsecs_t getDownTime() const { return mDownTime; } inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 3266b0740d..dc4978b836 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "Input" //#define LOG_NDEBUG 0 -#include #include #include @@ -434,7 +433,7 @@ void MotionEvent::transform(const float matrix[9]) { transformPoint(matrix, 0, 0, &originX, &originY); // Apply the transformation to cursor position. - if (!isnan(mXCursorPosition) && !isnan(mYCursorPosition)) { + if (isValidCursorPosition(mXCursorPosition, mYCursorPosition)) { float x = mXCursorPosition + oldXOffset; float y = mYCursorPosition + oldYOffset; transformPoint(matrix, x, y, &x, &y); diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index ec34f3e652..b879de6a74 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -603,9 +603,13 @@ TEST_F(MotionEventTest, Transform) { ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1); } - // Check cursor positions. - ASSERT_NEAR(sinf(PI_180 * (90 + ROTATION)) * RADIUS, event.getXCursorPosition(), 0.001); - ASSERT_NEAR(-cosf(PI_180 * (90 + ROTATION)) * RADIUS, event.getYCursorPosition(), 0.001); + // Check cursor positions. The original cursor position is at (3 + RADIUS, 2), where the center + // of the circle is (3, 2), so the cursor position is to the right of the center of the circle. + // The choice of triangular functions in this test defines the angle of rotation clockwise + // relative to the y-axis. Therefore the cursor position's angle is 90 degrees. Here we swap the + // triangular function so that we don't have to add the 90 degrees. + ASSERT_NEAR(cosf(PI_180 * ROTATION) * RADIUS, event.getXCursorPosition(), 0.001); + ASSERT_NEAR(sinf(PI_180 * ROTATION) * RADIUS, event.getYCursorPosition(), 0.001); // Applying the transformation should preserve the raw X and Y of the first point. ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001); diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp index be1370747c..1d8c365702 100644 --- a/services/inputflinger/InputDispatcher.cpp +++ b/services/inputflinger/InputDispatcher.cpp @@ -2766,7 +2766,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { ", policyFlags=0x%x, " "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, " "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, " - "mYCursorPosition=%f, downTime=%" PRId64, + "yCursorPosition=%f, downTime=%" PRId64, args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags, args->action, args->actionButton, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition, -- cgit v1.2.3-59-g8ed1b From ef44c2d08f0a7c04511b7fd027e2528919e15658 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 15 Jul 2019 15:27:22 -0700 Subject: [RenderEngine] Add cache contents to dumpsys We've had some high EGL utilization attributed to SurfaceFlinger recently, so adding info to dumpsys to hopefully catch a leak. Bug: 137514000 Test: dumpsys Change-Id: I22cf9eb01162d341c44dbe1440f74865dbf960fb --- libs/renderengine/gl/GLESRenderEngine.cpp | 21 ++++++++++++++++++++- libs/renderengine/gl/GLESRenderEngine.h | 15 +++++++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 6e7ec336e9..bf22e5cd60 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -837,6 +837,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer bool useFramebufferCache) { sp graphicBuffer = GraphicBuffer::from(nativeBuffer); if (useFramebufferCache) { + std::lock_guard lock(mFramebufferImageCacheMutex); for (const auto& image : mFramebufferImageCache) { if (image.first == graphicBuffer->getId()) { return image.second; @@ -852,6 +853,7 @@ EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer nativeBuffer, attributes); if (useFramebufferCache) { if (image != EGL_NO_IMAGE_KHR) { + std::lock_guard lock(mFramebufferImageCacheMutex); if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) { EGLImageKHR expired = mFramebufferImageCache.front().second; mFramebufferImageCache.pop_front(); @@ -1266,6 +1268,23 @@ void GLESRenderEngine::dump(std::string& result) { StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n", dataspaceDetails(static_cast(mDataSpace)).c_str(), dataspaceDetails(static_cast(mOutputDataSpace)).c_str()); + { + std::lock_guard lock(mRenderingMutex); + StringAppendF(&result, "RenderEngine image cache size: %zu\n", mImageCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, unused] : mImageCache) { + StringAppendF(&result, "0x%" PRIx64 "\n", id); + } + } + { + std::lock_guard lock(mFramebufferImageCacheMutex); + StringAppendF(&result, "RenderEngine framebuffer image cache size: %zu\n", + mFramebufferImageCache.size()); + StringAppendF(&result, "Dumping buffer ids...\n"); + for (const auto& [id, unused] : mFramebufferImageCache) { + StringAppendF(&result, "0x%" PRIx64 "\n", id); + } + } } GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) { @@ -1392,7 +1411,7 @@ bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) { } bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) { - std::lock_guard lock(mRenderingMutex); + std::lock_guard lock(mFramebufferImageCacheMutex); return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(), [=](std::pair image) { return image.first == bufferId; diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 70b704abce..2eebf9af85 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -79,17 +79,20 @@ public: EGLDisplay getEGLDisplay() const { return mEGLDisplay; } // Creates an output image for rendering to EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, - bool useFramebufferCache); + bool useFramebufferCache) + EXCLUDES(mFramebufferImageCacheMutex); // Test-only methods // Returns true iff mImageCache contains an image keyed by bufferId bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); // Returns true iff mFramebufferImageCache contains an image keyed by bufferId - bool isFramebufferImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); + bool isFramebufferImageCachedForTesting(uint64_t bufferId) + EXCLUDES(mFramebufferImageCacheMutex); protected: Framebuffer* getFramebufferForDrawing() override; - void dump(std::string& result) override; + void dump(std::string& result) override EXCLUDES(mRenderingMutex) + EXCLUDES(mFramebufferImageCacheMutex); size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -191,7 +194,11 @@ private: uint32_t mFramebufferImageCacheSize = 0; // Cache of output images, keyed by corresponding GraphicBuffer ID. - std::deque> mFramebufferImageCache; + std::deque> mFramebufferImageCache + GUARDED_BY(mFramebufferImageCacheMutex); + // The only reason why we have this mutex is so that we don't segfault when + // dumping info. + std::mutex mFramebufferImageCacheMutex; // Current dataspace of layer being rendered ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN; -- cgit v1.2.3-59-g8ed1b From 996bc421ea90965e384c947f5a68394afb95bd88 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 16 Jul 2019 14:15:33 -0700 Subject: Properly merge flags when merging transactions Test: atest SurfaceFlinger_test Change-Id: Ib1446c5afe00fd2588f7682f33cbbc6d6eb6a1ea --- libs/gui/LayerState.cpp | 5 +++-- services/surfaceflinger/tests/Transaction_test.cpp | 24 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6066421faf..aa07cbe0ab 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -267,8 +267,9 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eFlagsChanged) { what |= eFlagsChanged; - flags = other.flags; - mask = other.mask; + flags &= ~other.mask; + flags |= (other.flags & other.mask); + mask |= other.mask; } if (other.what & eLayerStackChanged) { what |= eLayerStackChanged; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index d5f65348d8..aed7b40872 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -4427,6 +4427,30 @@ TEST_F(LayerUpdateTest, MergingTransactions) { } } +TEST_F(LayerUpdateTest, MergingTransactionFlags) { + Transaction().hide(mFGSurfaceControl).apply(); + std::unique_ptr sc; + { + SCOPED_TRACE("before merge"); + ScreenCapture::captureScreen(&sc); + sc->expectBGColor(0, 12); + sc->expectBGColor(75, 75); + sc->expectBGColor(145, 145); + } + + Transaction t1, t2; + t1.show(mFGSurfaceControl); + t2.setFlags(mFGSurfaceControl, 0 /* flags */, layer_state_t::eLayerSecure /* mask */); + t1.merge(std::move(t2)); + t1.apply(); + + { + SCOPED_TRACE("after merge"); + ScreenCapture::captureScreen(&sc); + sc->expectFGColor(75, 75); + } +} + class ChildLayerTest : public LayerUpdateTest { protected: void SetUp() override { -- cgit v1.2.3-59-g8ed1b From f03652dd9df88182518a7046cf542076ea10d5ea Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 16 Jul 2019 17:56:56 -0700 Subject: Store layer state changes by layer handle in Transaction objects Layer state changes are stored in an unordered map with the surface control as the key and state changes as the value. This causes a few problems when merging the transactions. If transactions contained state changes from a cloned surface control then it will not be merged. This will cause ordering issues when the transaction is applied since the changes are stored in and unordered map. When parcelling transactions, a new surface control is created from the existing one and this surfaces the problem more frequently. Instead we store the layer changes by the layer handle which is consistent across processes. Test: atest SurfaceFlinger_test Test: go/wm-smoke Change-Id: I2e041d70ae24db2c1f26ada003532ad97f667167 --- libs/gui/LayerState.cpp | 2 -- libs/gui/SurfaceComposerClient.cpp | 40 +++++++++++++--------------- libs/gui/SurfaceControl.cpp | 4 +-- libs/gui/include/gui/LayerState.h | 3 --- libs/gui/include/gui/SurfaceComposerClient.h | 25 +++++++++-------- services/surfaceflinger/SurfaceFlinger.cpp | 28 +------------------ services/surfaceflinger/SurfaceFlinger.h | 1 - 7 files changed, 36 insertions(+), 67 deletions(-) (limited to 'libs') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 6066421faf..a09ceae7c6 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -169,12 +169,10 @@ status_t layer_state_t::read(const Parcel& input) } status_t ComposerState::write(Parcel& output) const { - output.writeStrongBinder(IInterface::asBinder(client)); return state.write(output); } status_t ComposerState::read(const Parcel& input) { - client = interface_cast(input.readStrongBinder()); return state.read(input); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c59fddfb9d..de36511a5b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -202,7 +202,8 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener * callbackIds to generate one super map that contains all the sp to sp * that could possibly exist for the callbacks. */ - std::unordered_map, sp, IBinderHash> surfaceControls; + std::unordered_map, sp, SurfaceComposerClient::IBinderHash> + surfaceControls; for (const auto& transactionStats : listenerStats.transactionStats) { for (auto callbackId : transactionStats.callbackIds) { auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId]; @@ -365,16 +366,16 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel if (count > parcel->dataSize()) { return BAD_VALUE; } - std::unordered_map, ComposerState, SCHash> composerStates; + std::unordered_map, ComposerState, IBinderHash> composerStates; composerStates.reserve(count); for (size_t i = 0; i < count; i++) { - sp surfaceControl = SurfaceControl::readFromParcel(parcel); + sp surfaceControlHandle = parcel->readStrongBinder(); ComposerState composerState; if (composerState.read(*parcel) == BAD_VALUE) { return BAD_VALUE; } - composerStates[surfaceControl] = composerState; + composerStates[surfaceControlHandle] = composerState; } InputWindowCommands inputWindowCommands; @@ -408,8 +409,8 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const } parcel->writeUint32(static_cast(mComposerStates.size())); - for (auto const& [surfaceControl, composerState] : mComposerStates) { - surfaceControl->writeToParcel(parcel); + for (auto const& [surfaceHandle, composerState] : mComposerStates) { + parcel->writeStrongBinder(surfaceHandle); composerState.write(*parcel); } @@ -418,11 +419,11 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { - for (auto const& kv : other.mComposerStates) { - if (mComposerStates.count(kv.first) == 0) { - mComposerStates[kv.first] = kv.second; + for (auto const& [surfaceHandle, composerState] : other.mComposerStates) { + if (mComposerStates.count(surfaceHandle) == 0) { + mComposerStates[surfaceHandle] = composerState; } else { - mComposerStates[kv.first].state.merge(kv.second.state); + mComposerStates[surfaceHandle].state.merge(composerState.state); } } @@ -465,14 +466,12 @@ void SurfaceComposerClient::Transaction::clear() { mDesiredPresentTime = -1; } -void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle, - const sp& client) { +void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle) { sp sf(ComposerService::getComposerService()); Vector composerStates; Vector displayStates; ComposerState s; - s.client = client; s.state.surface = handle; s.state.what |= layer_state_t::eReparent; s.state.parentHandleForChild = nullptr; @@ -499,8 +498,8 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { } size_t count = 0; - for (auto& [sc, cs] : mComposerStates) { - layer_state_t* s = getLayerState(sc); + for (auto& [handle, cs] : mComposerStates) { + layer_state_t* s = getLayerState(handle); if (!(s->what & layer_state_t::eBufferChanged)) { continue; } @@ -639,16 +638,15 @@ void SurfaceComposerClient::Transaction::setEarlyWakeup() { mEarlyWakeup = true; } -layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& sc) { - if (mComposerStates.count(sc) == 0) { +layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& handle) { + if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list ComposerState s; - s.client = sc->getClient()->mClient; - s.state.surface = sc->getHandle(); - mComposerStates[sc] = s; + s.state.surface = handle; + mComposerStates[handle] = s; } - return &(mComposerStates[sc].state); + return &(mComposerStates[handle].state); } void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback( diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index b9defdd120..071314f082 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -65,8 +65,8 @@ SurfaceControl::~SurfaceControl() { // Avoid reparenting the server-side surface to null if we are not the owner of it, // meaning that we retrieved it from another process. - if (mClient != nullptr && mHandle != nullptr && mOwned) { - SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient()); + if (mHandle != nullptr && mOwned) { + SurfaceComposerClient::doDropReferenceTransaction(mHandle); } release(); } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f438eb3d01..cbd1c8553b 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -206,7 +206,6 @@ struct layer_state_t { }; struct ComposerState { - sp client; layer_state_t state; status_t write(Parcel& output) const; status_t read(const Parcel& input); @@ -274,8 +273,6 @@ struct InputWindowCommands { }; static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) { - if (lhs.client < rhs.client) return -1; - if (lhs.client > rhs.client) return 1; if (lhs.state.surface < rhs.state.surface) return -1; if (lhs.state.surface > rhs.state.surface) return 1; return 0; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4dda97f5e1..22ab62da44 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -163,8 +163,7 @@ public: * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it * to null), but without needing an sp to avoid infinite ressurection. */ - static void doDropReferenceTransaction(const sp& handle, - const sp& client); + static void doDropReferenceTransaction(const sp& handle); /** * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is @@ -270,6 +269,12 @@ public: } }; + struct IBinderHash { + std::size_t operator()(const sp& iBinder) const { + return std::hash{}(iBinder.get()); + } + }; + struct TCLHash { std::size_t operator()(const sp& tcl) const { return std::hash{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr); @@ -286,7 +291,7 @@ public: }; class Transaction : Parcelable { - std::unordered_map, ComposerState, SCHash> mComposerStates; + std::unordered_map, ComposerState, IBinderHash> mComposerStates; SortedVector mDisplayStates; std::unordered_map, CallbackInfo, TCLHash> mListenerCallbacks; @@ -314,7 +319,10 @@ public: InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; - layer_state_t* getLayerState(const sp& sc); + layer_state_t* getLayerState(const sp& surfaceHandle); + layer_state_t* getLayerState(const sp& sc) { + return getLayerState(sc->getHandle()); + } DisplayState& getDisplayState(const sp& token); void cacheBuffers(); @@ -560,15 +568,10 @@ class TransactionCompletedListener : public BnTransactionCompletedListener { CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1; - struct IBinderHash { - std::size_t operator()(const sp& iBinder) const { - return std::hash{}(iBinder.get()); - } - }; - struct CallbackTranslation { TransactionCompletedCallback callbackFunction; - std::unordered_map, sp, IBinderHash> surfaceControls; + std::unordered_map, sp, SurfaceComposerClient::IBinderHash> + surfaceControls; }; std::unordered_map mCallbacks GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f1e3971811..9c612b459b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3655,27 +3655,6 @@ bool SurfaceFlinger::transactionFlushNeeded() { return !mTransactionQueues.empty(); } -bool SurfaceFlinger::containsAnyInvalidClientState(const Vector& states) { - for (const ComposerState& state : states) { - // Here we need to check that the interface we're given is indeed - // one of our own. A malicious client could give us a nullptr - // IInterface, or one of its own or even one of our own but a - // different type. All these situations would cause us to crash. - if (state.client == nullptr) { - return true; - } - - sp binder = IInterface::asBinder(state.client); - if (binder == nullptr) { - return true; - } - - if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) { - return true; - } - } - return false; -} bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector& states) { @@ -3714,10 +3693,6 @@ void SurfaceFlinger::setTransactionState(const Vector& states, Mutex::Autolock _l(mStateLock); - if (containsAnyInvalidClientState(states)) { - return; - } - // If its TransactionQueue already has a pending TransactionState or if it is pending auto itr = mTransactionQueues.find(applyToken); // if this is an animation frame, wait until prior animation frame has @@ -3929,9 +3904,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( const std::vector& listenerCallbacks, int64_t postTime, bool privileged) { const layer_state_t& s = composerState.state; - sp client(static_cast(composerState.client.get())); - sp layer(client->getLayerUser(s.surface)); + sp layer(fromHandle(s.surface)); if (layer == nullptr) { for (auto& listenerCallback : listenerCallbacks) { mTransactionCompletedThread.registerUnpresentedCallbackHandle( diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fa801afff8..30b6b69b17 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -582,7 +582,6 @@ private: void latchAndReleaseBuffer(const sp& layer); void commitTransaction() REQUIRES(mStateLock); void commitOffscreenLayers(); - bool containsAnyInvalidClientState(const Vector& states); bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, const Vector& states); uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime, -- cgit v1.2.3-59-g8ed1b From fb4c9862b29eb4bdf32e99587b647fb645458e49 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 22 Jul 2019 15:24:37 -0700 Subject: Fixing overflow bug Client should not be requesting such large buffers. Limit byte size to max(size_t) Bug: 137801859 Test: build, boot Change-Id: Idef0c1e926c180bfaf640b627046adba5d3043c3 --- libs/ui/GraphicBufferAllocator.cpp | 10 +++++++++- libs/ui/tests/GraphicBuffer_test.cpp | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index 0861a1f9a3..9c7d1fda90 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -20,6 +20,7 @@ #include +#include #include #include @@ -114,6 +115,14 @@ status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, if (!width || !height) width = height = 1; + const uint32_t bpp = bytesPerPixel(format); + if (std::numeric_limits::max() / width / height < static_cast(bpp)) { + ALOGE("Failed to allocate (%u x %u) layerCount %u format %d " + "usage %" PRIx64 ": Requesting too large a buffer size", + width, height, layerCount, format, usage); + return BAD_VALUE; + } + // Ensure that layerCount is valid. if (layerCount < 1) layerCount = 1; @@ -126,7 +135,6 @@ status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, if (error == NO_ERROR) { Mutex::Autolock _l(sLock); KeyedVector& list(sAllocList); - uint32_t bpp = bytesPerPixel(format); alloc_rec_t rec; rec.width = width; rec.height = height; diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp index a7c248c105..127f7eedd6 100644 --- a/libs/ui/tests/GraphicBuffer_test.cpp +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -35,6 +35,22 @@ constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; class GraphicBufferTest : public testing::Test {}; +TEST_F(GraphicBufferTest, AllocateNoError) { + PixelFormat format = PIXEL_FORMAT_RGBA_8888; + sp gb(new GraphicBuffer(kTestWidth, kTestHeight, format, kTestLayerCount, + kTestUsage, std::string("test"))); + ASSERT_EQ(NO_ERROR, gb->initCheck()); +} + +TEST_F(GraphicBufferTest, AllocateBadDimensions) { + PixelFormat format = PIXEL_FORMAT_RGBA_8888; + uint32_t width, height; + width = height = std::numeric_limits::max(); + sp gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage, + std::string("test"))); + ASSERT_EQ(BAD_VALUE, gb->initCheck()); +} + TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) { std::unique_ptr b1 = BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, -- cgit v1.2.3-59-g8ed1b From e3b57006c2f4604c0b31eaf9228ed336f5c47bf7 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Mon, 22 Jul 2019 17:18:52 +0200 Subject: Mark screen rotation as early (2/2) To decrease jank while rotating. Test: Rotate screen Bug: 138083790 Change-Id: I2b0d63bbf4143b9273a502ced451867f69e42636 Exempt-From-Owner-Approval: Already reviewed on qt-dev --- libs/gui/SurfaceComposerClient.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c59fddfb9d..16a4b353aa 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -448,6 +448,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mInputWindowCommands.merge(other.mInputWindowCommands); mContainsBuffer = other.mContainsBuffer; + mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; other.clear(); return *this; } -- cgit v1.2.3-59-g8ed1b From 937bb83a143631fcb25f0962aa95c1f850fdf023 Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Thu, 25 Jul 2019 17:48:31 -0700 Subject: Add setCursorPosition. When source is updated we need to update their values. Also renamed mX/YCursorPosition to mRawX/YCursorPosition to indicate it stores raw values (w/o applying offset). Bug: 134788085 Test: atest libinput_tests Change-Id: I1533d79a7542291974ff572d3aeaf9924e3f0751 --- include/input/Input.h | 14 ++++++++------ libs/input/Input.cpp | 35 ++++++++++++++++++++--------------- libs/input/tests/InputEvent_test.cpp | 10 ++++++++++ 3 files changed, 38 insertions(+), 21 deletions(-) (limited to 'libs') diff --git a/include/input/Input.h b/include/input/Input.h index ad8c233577..cbd1a412bf 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -469,14 +469,16 @@ public: inline float getYPrecision() const { return mYPrecision; } - inline float getRawXCursorPosition() const { return mXCursorPosition; } + inline float getRawXCursorPosition() const { return mRawXCursorPosition; } float getXCursorPosition() const; - inline float getRawYCursorPosition() const { return mYCursorPosition; } + inline float getRawYCursorPosition() const { return mRawYCursorPosition; } float getYCursorPosition() const; + void setCursorPosition(float x, float y); + static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); } inline nsecs_t getDownTime() const { return mDownTime; } @@ -623,8 +625,8 @@ public: void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, float xOffset, - float yOffset, float xPrecision, float yPrecision, float mXCursorPosition, - float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime, + float yOffset, float xPrecision, float yPrecision, float rawXCursorPosition, + float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); @@ -676,8 +678,8 @@ protected: float mYOffset; float mXPrecision; float mYPrecision; - float mXCursorPosition; - float mYCursorPosition; + float mRawXCursorPosition; + float mRawYCursorPosition; nsecs_t mDownTime; Vector mPointerProperties; Vector mSampleEventTimes; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index dc4978b836..34b305e548 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -238,8 +238,8 @@ void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, float xOffset, float yOffset, - float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, nsecs_t downTime, nsecs_t eventTime, + float xPrecision, float yPrecision, float rawXCursorPosition, + float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source, displayId); @@ -254,8 +254,8 @@ void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; - mXCursorPosition = xCursorPosition; - mYCursorPosition = yCursorPosition; + mRawXCursorPosition = rawXCursorPosition; + mRawYCursorPosition = rawYCursorPosition; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); @@ -277,8 +277,8 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; - mXCursorPosition = other->mXCursorPosition; - mYCursorPosition = other->mYCursorPosition; + mRawXCursorPosition = other->mRawXCursorPosition; + mRawYCursorPosition = other->mRawYCursorPosition; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; @@ -313,6 +313,11 @@ float MotionEvent::getYCursorPosition() const { return rawY + mYOffset; } +void MotionEvent::setCursorPosition(float x, float y) { + mRawXCursorPosition = x - mXOffset; + mRawYCursorPosition = y - mYOffset; +} + const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; } @@ -433,12 +438,12 @@ void MotionEvent::transform(const float matrix[9]) { transformPoint(matrix, 0, 0, &originX, &originY); // Apply the transformation to cursor position. - if (isValidCursorPosition(mXCursorPosition, mYCursorPosition)) { - float x = mXCursorPosition + oldXOffset; - float y = mYCursorPosition + oldYOffset; + if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) { + float x = mRawXCursorPosition + oldXOffset; + float y = mRawYCursorPosition + oldYOffset; transformPoint(matrix, x, y, &x, &y); - mXCursorPosition = x - mXOffset; - mYCursorPosition = y - mYOffset; + mRawXCursorPosition = x - mXOffset; + mRawYCursorPosition = y - mYOffset; } // Apply the transformation to all samples. @@ -480,8 +485,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); - mXCursorPosition = parcel->readFloat(); - mYCursorPosition = parcel->readFloat(); + mRawXCursorPosition = parcel->readFloat(); + mRawYCursorPosition = parcel->readFloat(); mDownTime = parcel->readInt64(); mPointerProperties.clear(); @@ -533,8 +538,8 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); parcel->writeFloat(mYPrecision); - parcel->writeFloat(mXCursorPosition); - parcel->writeFloat(mYCursorPosition); + parcel->writeFloat(mRawXCursorPosition); + parcel->writeFloat(mRawYCursorPosition); parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index b879de6a74..b90857c99c 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -665,4 +665,14 @@ TEST_F(MotionEventTest, Initialize_SetsCursorPosition) { ASSERT_EQ(600, event.getYCursorPosition()); } +TEST_F(MotionEventTest, SetCursorPosition) { + MotionEvent event; + initializeEventWithHistory(&event); + event.setSource(AINPUT_SOURCE_MOUSE); + + event.setCursorPosition(3, 4); + ASSERT_EQ(3, event.getXCursorPosition()); + ASSERT_EQ(4, event.getYCursorPosition()); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From 6c501ea04e486d9bf5c8a08d0d63dadcd9be83a9 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 24 Jul 2019 15:42:11 -0700 Subject: libtimeinstate: fix bug in clearUidCpuFreqTimes In a preallocated bpf hash table, deleting a map element makes it available for reuse without clearing the data it holds. This reuse can occur when a bpf program calls bpf_map_update_elem with a key not already present in the map. If the map is percpu, bpf_map_update_elem will overwrite the reused entry's data for the current CPU but not for other CPUs, resulting in stale data that is now associated with the wrong key. For time in state, this can show up as impossible data (e.g. reporting that a UID ran on one cluster at a frequency only available on a different cluster), which is detected by the SingleAndAllUidConsistent test since getUidCpuFreqTimes() only looks up potentially valid keys while getUidsCpuFreqTimes() iterates through every map entry. Avoid this problem by zeroing out each entry's data prior to deleting it from the map. Also modify getUidCpuFreqTimes and getUidsCpuFreqTimes to check for impossible data and fail if any is detected, since it's a sign that other map entries may also be wrong. Bug: 138317993 Test: libtimeinstate_test can now be run repeatedly without SingleAndAllUidConsistent test eventually failing Signed-off-by: Connor O'Brien Change-Id: I17dd407f897d1e86eb85cc99842a581d88e5bc78 --- libs/cputimeinstate/cputimeinstate.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 0e68e628b6..a02b28551e 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -167,9 +168,12 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui return {}; } for (uint32_t i = 0; i < gNPolicies; ++i) { - if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue; uint64_t time = 0; for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; + if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) { + if (time != 0) return {}; + else continue; + } idxs[i] += 1; out[i].emplace_back(time); } @@ -209,10 +213,12 @@ getUidsCpuFreqTimes() { } for (size_t policy = 0; policy < gNPolicies; ++policy) { - for (const auto &cpu : gPolicyCpus[policy]) { - auto freqIdx = policyFreqIdxs[policy][key.freq]; - map[key.uid][policy][freqIdx] += val.ar[cpu]; - } + uint64_t time = 0; + for (const auto &cpu : gPolicyCpus[policy]) time += val.ar[cpu]; + if (!time) continue; + auto it = policyFreqIdxs[policy].find(key.freq); + if (it == policyFreqIdxs[policy].end()) return android::netdutils::Status(-1); + map[key.uid][policy][it->second] += time; } return android::netdutils::status::ok; }; @@ -225,9 +231,10 @@ bool clearUidCpuFreqTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return false; time_key_t key = {.uid = uid, .freq = 0}; - std::vector idxs(gNPolicies, 0); + std::vector vals(get_nprocs_conf(), 0); for (auto freq : gAllFreqs) { key.freq = freq; + if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false; if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false; } return true; -- cgit v1.2.3-59-g8ed1b From 9236e872cd315c36bca7625751f16ec0817348c7 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Thu, 6 Jun 2019 17:48:20 -0700 Subject: libtimeinstate: support cpufreq fast switching In order to support kernels that use fast frequency switching, the time_in_state BPF program needs to know which CPUs are members of which cpufreq policies. Add logic to startTrackingUidCpuFreqTimes() to write this information into a BPF map in order to make it available to the BPF program. Test: libtimeinstate_test passes Change-Id: I47b38457766d21c2aa0879f156fc90757c0db705 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index a02b28551e..6f50a1e623 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -141,6 +141,17 @@ static bool attachTracepointProgram(const std::string &eventType, const std::str // This function should *not* be called while tracking is already active; doing so is unnecessary // and can lead to accounting errors. bool startTrackingUidCpuFreqTimes() { + if (!initGlobals()) return false; + + unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); + if (fd < 0) return false; + + for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) { + for (auto &cpu : gPolicyCpus[i]) { + if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false; + } + } + return attachTracepointProgram("sched", "sched_switch") && attachTracepointProgram("power", "cpu_frequency"); } -- cgit v1.2.3-59-g8ed1b From 16ab1709fc9bef67fc1655128f54a6bce182de50 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Fri, 7 Jun 2019 16:39:49 -0700 Subject: libtimeinstate: change map format to improve performance By storing times for up to 32 freqs in each map value instead of one time per value, we can drastically reduce the number of syscalls required to get the data for a single UID and for all UIDs. This translates into a better than 3x speedup in getUidsCpuFreqTimes(). Test: libtimeinstate_test passes Bug: 138317993 Change-Id: I0d2d4d5fc99a82179a84a9aa83101bc55ddbc0e4 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 134 +++++++++++++++++++------------- libs/cputimeinstate/testtimeinstate.cpp | 6 +- libs/cputimeinstate/timeinstate.h | 11 ++- 3 files changed, 91 insertions(+), 60 deletions(-) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 6f50a1e623..4c8d52efd9 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -49,6 +49,7 @@ namespace bpf { static std::mutex gInitializedMutex; static bool gInitialized = false; static uint32_t gNPolicies = 0; +static uint32_t gNCpus = 0; static std::vector> gPolicyFreqs; static std::vector> gPolicyCpus; static std::set gAllFreqs; @@ -86,6 +87,8 @@ static bool initGlobals() { std::lock_guard guard(gInitializedMutex); if (gInitialized) return true; + gNCpus = get_nprocs_conf(); + struct dirent **dirlist; const char basepath[] = "/sys/devices/system/cpu/cpufreq"; int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles); @@ -152,6 +155,21 @@ bool startTrackingUidCpuFreqTimes() { } } + unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); + if (fd2 < 0) return false; + freq_idx_key_t key; + for (uint32_t i = 0; i < gNPolicies; ++i) { + key.policy = i; + for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) { + key.freq = gPolicyFreqs[i][j]; + // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq. + // The uid_times map still uses 0-based indexes, and the sched_switch program handles + // conversion between them, so this does not affect our map reading code. + uint32_t idx = j + 1; + if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false; + } + } + return attachTracepointProgram("sched", "sched_switch") && attachTracepointProgram("power", "cpu_frequency"); } @@ -163,30 +181,33 @@ bool startTrackingUidCpuFreqTimes() { // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq. std::optional>> getUidCpuFreqTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return {}; - time_key_t key = {.uid = uid, .freq = 0}; - - std::vector> out(gNPolicies); - std::vector idxs(gNPolicies, 0); - - val_t value; - for (uint32_t freq : gAllFreqs) { - key.freq = freq; - int ret = findMapEntry(gMapFd, &key, &value); - if (ret) { - if (errno == ENOENT) - memset(&value.ar, 0, sizeof(value.ar)); - else - return {}; + + std::vector> out; + uint32_t maxFreqCount = 0; + for (const auto &freqList : gPolicyFreqs) { + if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); + out.emplace_back(freqList.size(), 0); + } + + std::vector vals(gNCpus); + time_key_t key = {.uid = uid}; + for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) { + key.bucket = i; + if (findMapEntry(gMapFd, &key, vals.data())) { + if (errno != ENOENT) return {}; + continue; } - for (uint32_t i = 0; i < gNPolicies; ++i) { - uint64_t time = 0; - for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; - if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) { - if (time != 0) return {}; - else continue; + + auto offset = i * FREQS_PER_ENTRY; + auto nextOffset = (i + 1) * FREQS_PER_ENTRY; + for (uint32_t j = 0; j < gNPolicies; ++j) { + if (offset >= gPolicyFreqs[j].size()) continue; + auto begin = out[j].begin() + offset; + auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end(); + + for (const auto &cpu : gPolicyCpus[j]) { + std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus()); } - idxs[i] += 1; - out[i].emplace_back(time); } } @@ -202,49 +223,52 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui std::optional>>> getUidsCpuFreqTimes() { if (!gInitialized && !initGlobals()) return {}; + time_key_t key, prevKey; + std::unordered_map>> map; + if (getFirstMapKey(gMapFd, &key)) { + if (errno == ENOENT) return map; + return std::nullopt; + } - int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); - if (fd < 0) return {}; - BpfMap m(fd); + std::vector> mapFormat; + for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); - std::vector> policyFreqIdxs; - for (uint32_t i = 0; i < gNPolicies; ++i) { - std::unordered_map freqIdxs; - for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j; - policyFreqIdxs.emplace_back(freqIdxs); - } - std::unordered_map>> map; - auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val, - const BpfMap &) { - if (map.find(key.uid) == map.end()) { - map[key.uid].resize(gNPolicies); - for (uint32_t i = 0; i < gNPolicies; ++i) { - map[key.uid][i].resize(gPolicyFreqs[i].size(), 0); - } - } + std::vector vals(gNCpus); + do { + if (findMapEntry(gMapFd, &key, vals.data())) return {}; + if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); - for (size_t policy = 0; policy < gNPolicies; ++policy) { - uint64_t time = 0; - for (const auto &cpu : gPolicyCpus[policy]) time += val.ar[cpu]; - if (!time) continue; - auto it = policyFreqIdxs[policy].find(key.freq); - if (it == policyFreqIdxs[policy].end()) return android::netdutils::Status(-1); - map[key.uid][policy][it->second] += time; + auto offset = key.bucket * FREQS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY; + for (uint32_t i = 0; i < gNPolicies; ++i) { + if (offset >= gPolicyFreqs[i].size()) continue; + auto begin = map[key.uid][i].begin() + offset; + auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY : + map[key.uid][i].end(); + for (const auto &cpu : gPolicyCpus[i]) { + std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus()); + } } - return android::netdutils::status::ok; - }; - if (isOk(m.iterateWithValue(fn))) return map; - return {}; + prevKey = key; + } while (!getNextMapKey(gMapFd, &prevKey, &key)); + if (errno != ENOENT) return {}; + return map; } // Clear all time in state data for a given uid. Returns false on error, true otherwise. bool clearUidCpuFreqTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return false; - time_key_t key = {.uid = uid, .freq = 0}; - std::vector vals(get_nprocs_conf(), 0); - for (auto freq : gAllFreqs) { - key.freq = freq; + time_key_t key = {.uid = uid}; + + uint32_t maxFreqCount = 0; + for (const auto &freqList : gPolicyFreqs) { + if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); + } + + val_t zeros = {0}; + std::vector vals(gNCpus, zeros); + for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) { if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false; if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false; } diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 6347de166a..39007e4603 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -126,10 +126,10 @@ TEST(TimeInStateTest, RemoveUid) { ASSERT_GE(fd, 0); time_key_t k; ASSERT_FALSE(getFirstMapKey(fd, &k)); - val_t val; - ASSERT_FALSE(findMapEntry(fd, &k, &val)); + std::vector vals(get_nprocs_conf()); + ASSERT_FALSE(findMapEntry(fd, &k, vals.data())); k.uid = uid; - ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST)); + ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST)); } auto times = getUidCpuFreqTimes(uid); ASSERT_TRUE(times.has_value()); diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h index cf66ae7077..41d0af07a2 100644 --- a/libs/cputimeinstate/timeinstate.h +++ b/libs/cputimeinstate/timeinstate.h @@ -18,11 +18,18 @@ #define BPF_FS_PATH "/sys/fs/bpf/" +#define FREQS_PER_ENTRY 32 + struct time_key_t { uint32_t uid; - uint32_t freq; + uint32_t bucket; }; struct val_t { - uint64_t ar[100]; + uint64_t ar[FREQS_PER_ENTRY]; +}; + +struct freq_idx_key_t { + uint32_t policy; + uint32_t freq; }; -- cgit v1.2.3-59-g8ed1b From f8e4a3430015900205d63748447a946a792e572e Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 29 Jul 2019 13:27:16 -0700 Subject: libgui: remove redundant eglQueryStringImplementationANDROID Test: build, flash and boot Change-Id: I48cbee82015551b5cd502565d76fe6038b2a50c7 --- libs/gui/GLConsumer.cpp | 1 - libs/gui/tests/SurfaceTextureClient_test.cpp | 2 -- 2 files changed, 3 deletions(-) (limited to 'libs') diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 8199c98582..59f1bcd24e 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -46,7 +46,6 @@ #include #include -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" #define EGL_PROTECTED_CONTENT_EXT 0x32C0 diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 65e09f2540..c85e84489d 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -28,8 +28,6 @@ #include #include -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - namespace android { class SurfaceTextureClientTest : public ::testing::Test { -- cgit v1.2.3-59-g8ed1b From 2249c88ec56f2524a3c5bee5cbca232eae1357d1 Mon Sep 17 00:00:00 2001 From: Stan Rokita Date: Tue, 30 Jul 2019 14:23:49 -0700 Subject: Fix null pointer deref in libsensor SensorServer When trying to create a senor direct connection, check that native handle resource is not null, and if so return BAD_VALUE error. Bug: 135051254 Test: Load onto device and try "service call sensorservice 5" commands that have no arguments and random arguments. Both throw new error and do not crash system as hoped. Change-Id: Ie2eaf1a17843da89927293e408768bfbaaf86ec8 --- libs/sensor/ISensorServer.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libs') diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index 5200545a53..8ed09f8ff0 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -199,6 +199,10 @@ status_t BnSensorServer::onTransact( int32_t type = data.readInt32(); int32_t format = data.readInt32(); native_handle_t *resource = data.readNativeHandle(); + // Avoid a crash in native_handle_close if resource is nullptr + if (resource == nullptr) { + return BAD_VALUE; + } sp ch = createSensorDirectConnection(opPackageName, size, type, format, resource); native_handle_close(resource); -- cgit v1.2.3-59-g8ed1b From a08194b0086226364d5e045e52ff19028601bbdc Mon Sep 17 00:00:00 2001 From: mamik Date: Thu, 25 Jul 2019 13:07:21 -0700 Subject: Updating ConfigurationDataGet api to include edid data. Bug: 138398637 Test: manual - ran through modified unit test to make sure the edid data was returned on the MTP 845. Change-Id: I171cf90d005a09a9cb6ee1081efee653cce47c4a --- .../libdisplay/include/private/dvr/display_protocol.h | 3 ++- libs/vr/libdvr/include/dvr/dvr_api.h | 2 ++ libs/vr/libvrflinger/display_service.cpp | 18 ++++++++++++++++++ libs/vr/libvrflinger/display_service.h | 4 ++++ 4 files changed, 26 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h index 3786d1d5e9..861dc6c2a0 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h +++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h @@ -191,7 +191,8 @@ struct SurfaceInfo { enum class ConfigFileType : uint32_t { kLensMetrics, kDeviceMetrics, - kDeviceConfiguration + kDeviceConfiguration, + kDeviceEdid }; struct DisplayProtocol { diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h index e383bb2cb3..b7abb99559 100644 --- a/libs/vr/libdvr/include/dvr/dvr_api.h +++ b/libs/vr/libdvr/include/dvr/dvr_api.h @@ -85,6 +85,8 @@ enum { DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1, // Request the per device configuration data file. DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2, + // Request the edid data for the display. + DVR_CONFIGURATION_DATA_DEVICE_EDID = 3, }; // dvr_display_manager.h diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 87162c0b5a..8980a92776 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -44,6 +44,18 @@ DisplayService::DisplayService(Hwc2::Composer* hidl, Endpoint::Create(display::DisplayProtocol::kClientPath)) { hardware_composer_.Initialize( hidl, primary_display_id, request_display_callback); + + uint8_t port; + const auto error = hidl->getDisplayIdentificationData( + primary_display_id, &port, &display_identification_data_); + if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { + if (error != + android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { + ALOGI("DisplayService: identification data error\n"); + } else { + ALOGI("DisplayService: identification data unsupported\n"); + } + } } bool DisplayService::IsInitialized() const { @@ -204,6 +216,12 @@ pdx::Status DisplayService::OnGetConfigurationData( case display::ConfigFileType::kDeviceConfiguration: property_name = kDvrDeviceConfigProperty; break; + case display::ConfigFileType::kDeviceEdid: + if (display_identification_data_.size() == 0) { + return ErrorStatus(ENOENT); + } + return std::string(display_identification_data_.begin(), + display_identification_data_.end()); default: return ErrorStatus(EINVAL); } diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index e0f2eddfea..d45a61fad7 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -18,6 +18,8 @@ #include "epoll_event_dispatcher.h" #include "hardware_composer.h" +#include "DisplayHardware/DisplayIdentification.h" + namespace android { namespace dvr { @@ -117,6 +119,8 @@ class DisplayService : public pdx::ServiceBase { DisplayService(const DisplayService&) = delete; void operator=(const DisplayService&) = delete; + + DisplayIdentificationData display_identification_data_; }; } // namespace dvr -- cgit v1.2.3-59-g8ed1b From 362720724944a779fa754709602ec67175aeace2 Mon Sep 17 00:00:00 2001 From: Fedor Kudasov Date: Thu, 4 Jul 2019 12:53:57 +0100 Subject: Enable surface for host Bug: 117921091 Test: all tests should pass Change-Id: I222ddcfda80c96726d96158173fcc1015abf7d36 --- libs/ui/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'libs') diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 2cc6857744..2bbb0ee50a 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -187,3 +187,11 @@ subdirs = [ "tests", "tools", ] + +filegroup { + name: "libui_host_common", + srcs: [ + "Rect.cpp", + "PixelFormat.cpp" + ], +} -- cgit v1.2.3-59-g8ed1b From 3649106e95f8fe5a733b5113ba76d7a3f4a0b85c Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Fri, 26 Jul 2019 14:41:43 -0700 Subject: Adding test to test closer boundary for overflow Bug: 137801859 Test: build, boot, GraphicBuffer_test Change-Id: Ic5c74a52dcf325c9151f63bd9bbb11ea17222b0b --- libs/ui/tests/GraphicBuffer_test.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'libs') diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp index 127f7eedd6..5e0b094b7b 100644 --- a/libs/ui/tests/GraphicBuffer_test.cpp +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -44,11 +44,28 @@ TEST_F(GraphicBufferTest, AllocateNoError) { TEST_F(GraphicBufferTest, AllocateBadDimensions) { PixelFormat format = PIXEL_FORMAT_RGBA_8888; + if (std::numeric_limits::max() / std::numeric_limits::max() / + bytesPerPixel(format) >= + std::numeric_limits::max()) { + GTEST_SUCCEED() << "Cannot overflow with this format"; + } uint32_t width, height; width = height = std::numeric_limits::max(); sp gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage, std::string("test"))); ASSERT_EQ(BAD_VALUE, gb->initCheck()); + + const size_t targetArea = std::numeric_limits::max() / bytesPerPixel(format); + const size_t widthCandidate = targetArea / std::numeric_limits::max(); + if (widthCandidate == 0) { + width = 1; + } else { + width = std::numeric_limits::max(); + } + height = (targetArea / width) + 1; + sp gb2(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage, + std::string("test"))); + ASSERT_EQ(BAD_VALUE, gb2->initCheck()); } TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) { -- cgit v1.2.3-59-g8ed1b From 8384682fd25b54921fd74288788f2a9299dd8dba Mon Sep 17 00:00:00 2001 From: Atif Niyaz Date: Thu, 18 Jul 2019 15:17:40 -0700 Subject: Seperate LatencyStatistics from InputReader Test: atest LatencyStatisticsTest Change-Id: I22a39cd5bef7fa9180bc1ee1fd9478a2cf872e83 --- include/input/LatencyStatistics.h | 59 +++++++++++++++++++ libs/input/Android.bp | 1 + libs/input/LatencyStatistics.cpp | 90 +++++++++++++++++++++++++++++ libs/input/tests/Android.bp | 1 + libs/input/tests/LatencyStatistics_test.cpp | 72 +++++++++++++++++++++++ services/inputflinger/InputReader.cpp | 21 +++---- services/inputflinger/InputReader.h | 72 ++--------------------- 7 files changed, 237 insertions(+), 79 deletions(-) create mode 100644 include/input/LatencyStatistics.h create mode 100644 libs/input/LatencyStatistics.cpp create mode 100644 libs/input/tests/LatencyStatistics_test.cpp (limited to 'libs') diff --git a/include/input/LatencyStatistics.h b/include/input/LatencyStatistics.h new file mode 100644 index 0000000000..bd86266901 --- /dev/null +++ b/include/input/LatencyStatistics.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_INPUT_STATISTICS_H +#define _UI_INPUT_STATISTICS_H + +#include + +#include + +namespace android { + +class LatencyStatistics { +private: + /* Minimum sample recorded */ + float mMin; + /* Maximum sample recorded */ + float mMax; + /* Sum of all samples recorded */ + float mSum; + /* Sum of all the squares of samples recorded */ + float mSum2; + /* Count of all samples recorded */ + size_t mCount; + /* The last time statistics were reported */ + std::chrono::steady_clock::time_point mLastReportTime; + /* Statistics Report Frequency */ + const std::chrono::seconds mReportPeriod; + +public: + LatencyStatistics(std::chrono::seconds period); + + void addValue(float); + void reset(); + bool shouldReport(); + + float getMean(); + float getMin(); + float getMax(); + float getStDev(); + size_t getCount(); +}; + +} // namespace android + +#endif // _UI_INPUT_STATISTICS_H diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 2d788119cd..17138506e5 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -48,6 +48,7 @@ cc_library { "InputTransport.cpp", "InputWindow.cpp", "ISetInputWindowsListener.cpp", + "LatencyStatistics.cpp", "VelocityControl.cpp", "VelocityTracker.cpp", ], diff --git a/libs/input/LatencyStatistics.cpp b/libs/input/LatencyStatistics.cpp new file mode 100644 index 0000000000..e343578e00 --- /dev/null +++ b/libs/input/LatencyStatistics.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 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 + +#include + +#include +#include + +namespace android { + +LatencyStatistics::LatencyStatistics(std::chrono::seconds period) : mReportPeriod(period) { + reset(); +} + +/** + * Add a raw value to the statistics + */ +void LatencyStatistics::addValue(float value) { + if (value < mMin) { + mMin = value; + } + if (value > mMax) { + mMax = value; + } + mSum += value; + mSum2 += value * value; + mCount++; +} + +/** + * Get the mean. Should not be called if no samples have been added. + */ +float LatencyStatistics::getMean() { + return mSum / mCount; +} + +/** + * Get the standard deviation. Should not be called if no samples have been added. + */ +float LatencyStatistics::getStDev() { + float mean = getMean(); + return sqrt(mSum2 / mCount - mean * mean); +} + +float LatencyStatistics::getMin() { + return mMin; +} + +float LatencyStatistics::getMax() { + return mMax; +} + +size_t LatencyStatistics::getCount() { + return mCount; +} + +/** + * Reset internal state. The variable 'when' is the time when the data collection started. + * Call this to start a new data collection window. + */ +void LatencyStatistics::reset() { + mMax = std::numeric_limits::lowest(); + mMin = std::numeric_limits::max(); + mSum = 0; + mSum2 = 0; + mCount = 0; + mLastReportTime = std::chrono::steady_clock::now(); +} + +bool LatencyStatistics::shouldReport() { + std::chrono::duration timeSinceReport = std::chrono::steady_clock::now() - mLastReportTime; + return mCount != 0 && timeSinceReport > mReportPeriod; +} + +} // namespace android diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index ade931e01a..c1c35e1b89 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -7,6 +7,7 @@ cc_test { "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", "InputWindow_test.cpp", + "LatencyStatistics_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", ], diff --git a/libs/input/tests/LatencyStatistics_test.cpp b/libs/input/tests/LatencyStatistics_test.cpp new file mode 100644 index 0000000000..6d1cab4187 --- /dev/null +++ b/libs/input/tests/LatencyStatistics_test.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 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 +#include +#include +#include + +namespace android { +namespace test { + +TEST(LatencyStatisticsTest, ResetStats) { + LatencyStatistics stats{5min}; + stats.addValue(5.0); + stats.addValue(19.3); + stats.addValue(20); + stats.reset(); + + ASSERT_EQ(stats.getCount(), 0u); + ASSERT_EQ(std::isnan(stats.getStDev()), true); + ASSERT_EQ(std::isnan(stats.getMean()), true); +} + +TEST(LatencyStatisticsTest, AddStatsValue) { + LatencyStatistics stats{5min}; + stats.addValue(5.0); + + ASSERT_EQ(stats.getMin(), 5.0); + ASSERT_EQ(stats.getMax(), 5.0); + ASSERT_EQ(stats.getCount(), 1u); + ASSERT_EQ(stats.getMean(), 5.0); + ASSERT_EQ(stats.getStDev(), 0.0); +} + +TEST(LatencyStatisticsTest, AddMultipleStatsValue) { + LatencyStatistics stats{5min}; + stats.addValue(4.0); + stats.addValue(6.0); + stats.addValue(8.0); + stats.addValue(10.0); + + float stdev = stats.getStDev(); + + ASSERT_EQ(stats.getMin(), 4.0); + ASSERT_EQ(stats.getMax(), 10.0); + ASSERT_EQ(stats.getCount(), 4u); + ASSERT_EQ(stats.getMean(), 7.0); + ASSERT_EQ(stdev * stdev, 5.0); +} + +TEST(LatencyStatisticsTest, ShouldReportStats) { + LatencyStatistics stats{0min}; + stats.addValue(5.0); + + ASSERT_EQ(stats.shouldReport(), true); +} + +} // namespace test +} // namespace android \ No newline at end of file diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index eee49d5e2a..df5dcafec9 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -85,9 +85,6 @@ static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); // data. static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); -// How often to report input event statistics -static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60); - // --- Static Functions --- template @@ -4314,16 +4311,14 @@ void TouchInputMapper::clearStylusDataPendingFlags() { } void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) { - nsecs_t now = systemTime(CLOCK_MONOTONIC); - nsecs_t latency = now - evdevTime; - mStatistics.addValue(nanoseconds_to_microseconds(latency)); - nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime; - if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) { - android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, - mStatistics.min, mStatistics.max, - mStatistics.mean(), mStatistics.stdev(), mStatistics.count); - mStatistics.reset(now); - } + if (mStatistics.shouldReport()) { + android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mStatistics.getMin(), + mStatistics.getMax(), mStatistics.getMean(), + mStatistics.getStDev(), mStatistics.getCount()); + mStatistics.reset(); + } + nsecs_t latency = nanoseconds_to_microseconds(systemTime(CLOCK_MONOTONIC) - evdevTime); + mStatistics.addValue(latency); } void TouchInputMapper::process(const RawEvent* rawEvent) { diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index 0c08e7da38..33763b6cdf 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -24,14 +24,15 @@ #include #include +#include #include #include #include -#include +#include #include +#include #include #include -#include #include #include @@ -569,69 +570,6 @@ struct CookedPointerData { } }; -/** - * Basic statistics information. - * Keep track of min, max, average, and standard deviation of the received samples. - * Used to report latency information about input events. - */ -struct LatencyStatistics { - float min; - float max; - // Sum of all samples - float sum; - // Sum of squares of all samples - float sum2; - // The number of samples - size_t count; - // The last time statistics were reported. - nsecs_t lastReportTime; - - LatencyStatistics() { - reset(systemTime(SYSTEM_TIME_MONOTONIC)); - } - - inline void addValue(float x) { - if (x < min) { - min = x; - } - if (x > max) { - max = x; - } - sum += x; - sum2 += x * x; - count++; - } - - // Get the average value. Should not be called if no samples have been added. - inline float mean() { - if (count == 0) { - return 0; - } - return sum / count; - } - - // Get the standard deviation. Should not be called if no samples have been added. - inline float stdev() { - if (count == 0) { - return 0; - } - float average = mean(); - return sqrt(sum2 / count - average * average); - } - - /** - * Reset internal state. The variable 'when' is the time when the data collection started. - * Call this to start a new data collection window. - */ - inline void reset(nsecs_t when) { - max = 0; - min = std::numeric_limits::max(); - sum = 0; - sum2 = 0; - count = 0; - lastReportTime = when; - } -}; /* Keeps track of the state of single-touch protocol. */ class SingleTouchMotionAccumulator { @@ -1571,8 +1509,10 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + static constexpr std::chrono::duration STATS_REPORT_PERIOD = 5min; + // Latency statistics for touch events - struct LatencyStatistics mStatistics; + LatencyStatistics mStatistics{STATS_REPORT_PERIOD}; std::optional findViewport(); -- cgit v1.2.3-59-g8ed1b From 3d3fa52c8bbe481ffb87d75e24725444bef0b939 Mon Sep 17 00:00:00 2001 From: Atif Niyaz Date: Thu, 25 Jul 2019 11:12:39 -0700 Subject: Move LatencyStatistics collection from InputReader to InputTransport This move allows us to grab a bigger context of how much time a motion event is spent from the kernel to right before the event was published. Test: Modified LatencyStats to report ever 10 seconds. Utilized logs to check that logs were reporting every 10 seconds. Checked also using logs that data was being added and calculated correctly. Change-Id: Iee0f9a2155e93ae77de5a5cd8b9fd1506186c60f Signed-off-by: Atif Niyaz --- include/input/InputTransport.h | 12 ++++++++++-- libs/input/Android.bp | 3 ++- libs/input/InputTransport.cpp | 16 ++++++++++++++++ services/inputflinger/Android.bp | 1 - services/inputflinger/InputReader.cpp | 13 ------------- services/inputflinger/InputReader.h | 8 -------- 6 files changed, 28 insertions(+), 25 deletions(-) (limited to 'libs') diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index df23f613c8..690e0a11c8 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -31,13 +31,16 @@ #include +#include + #include #include +#include +#include #include -#include #include +#include #include -#include namespace android { class Parcel; @@ -286,7 +289,12 @@ public: status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled); private: + static constexpr std::chrono::duration TOUCH_STATS_REPORT_PERIOD = 5min; + sp mChannel; + LatencyStatistics mTouchStatistics{TOUCH_STATS_REPORT_PERIOD}; + + void reportTouchEventForStatistics(nsecs_t evdevTime); }; /* diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 17138506e5..7749e66c4d 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -56,7 +56,8 @@ cc_library { shared_libs: [ "libutils", "libbinder", - "libui" + "libui", + "libstatslog", ], sanitize: { diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 904a6feb03..2ff301e270 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -34,6 +34,7 @@ #include #include +#include using android::base::StringPrintf; @@ -531,6 +532,10 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); } + + if (source == AINPUT_SOURCE_TOUCHSCREEN) { + reportTouchEventForStatistics(eventTime); + } return mChannel->sendMessage(&msg); } @@ -557,6 +562,17 @@ status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandle return OK; } +void InputPublisher::reportTouchEventForStatistics(nsecs_t evdevTime) { + if (mTouchStatistics.shouldReport()) { + android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mTouchStatistics.getMin(), + mTouchStatistics.getMax(), mTouchStatistics.getMean(), + mTouchStatistics.getStDev(), mTouchStatistics.getCount()); + mTouchStatistics.reset(); + } + nsecs_t latency = nanoseconds_to_microseconds(systemTime(CLOCK_MONOTONIC) - evdevTime); + mTouchStatistics.addValue(latency); +} + // --- InputConsumer --- InputConsumer::InputConsumer(const sp& channel) : diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 8dd4d1df63..bdee6fe043 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -88,7 +88,6 @@ cc_library_shared { "libui", "libutils", "libhardware_legacy", - "libstatslog", ], header_libs: [ diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index df5dcafec9..d565e3ab38 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -57,7 +57,6 @@ #include #include #include -#include #define INDENT " " #define INDENT2 " " @@ -4310,24 +4309,12 @@ void TouchInputMapper::clearStylusDataPendingFlags() { mExternalStylusFusionTimeout = LLONG_MAX; } -void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) { - if (mStatistics.shouldReport()) { - android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mStatistics.getMin(), - mStatistics.getMax(), mStatistics.getMean(), - mStatistics.getStDev(), mStatistics.getCount()); - mStatistics.reset(); - } - nsecs_t latency = nanoseconds_to_microseconds(systemTime(CLOCK_MONOTONIC) - evdevTime); - mStatistics.addValue(latency); -} - void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - reportEventForStatistics(rawEvent->when); sync(rawEvent->when); } } diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index 33763b6cdf..e434869996 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -1509,11 +1508,6 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; - static constexpr std::chrono::duration STATS_REPORT_PERIOD = 5min; - - // Latency statistics for touch events - LatencyStatistics mStatistics{STATS_REPORT_PERIOD}; - std::optional findViewport(); void resetExternalStylus(); @@ -1582,8 +1576,6 @@ private: static void assignPointerIds(const RawState* last, RawState* current); - void reportEventForStatistics(nsecs_t evdevTime); - const char* modeToString(DeviceMode deviceMode); }; -- cgit v1.2.3-59-g8ed1b From 49b9ac79f8ca475af1e98f098f803b593b0a02d6 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 5 Aug 2019 16:57:17 -0700 Subject: libgraphicsenv: get linker symbols from real header Test: build, flash and boot Change-Id: I181430f0f0caef6ee5590c2ed2bf3e7e90e4ed0d --- libs/graphicsenv/Android.bp | 4 ++++ libs/graphicsenv/GraphicsEnv.cpp | 17 +---------------- 2 files changed, 5 insertions(+), 16 deletions(-) (limited to 'libs') diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index 56521bf2b4..f11cf62e50 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -32,5 +32,9 @@ cc_library_shared { "libutils", ], + header_libs: [ + "libnativeloader-dummy-headers", + ], + export_include_dirs: ["include"], } diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 3e29e88b20..7f8d3a66b5 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -39,22 +40,6 @@ #include #include -// TODO(b/37049319) Get this from a header once one exists -extern "C" { -android_namespace_t* android_get_exported_namespace(const char*); -android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path, - const char* default_library_path, uint64_t type, - const char* permitted_when_isolated_path, - android_namespace_t* parent); -bool android_link_namespaces(android_namespace_t* from, android_namespace_t* to, - const char* shared_libs_sonames); - -enum { - ANDROID_NAMESPACE_TYPE_ISOLATED = 1, - ANDROID_NAMESPACE_TYPE_SHARED = 2, -}; -} - // TODO(ianelliott@): Get the following from an ANGLE header: #define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting // Version-2 API: -- cgit v1.2.3-59-g8ed1b From 472cab0a611317cc2a8a50cb9897018cee8d79e3 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Mon, 5 Aug 2019 17:57:41 -0700 Subject: GpuStats: fix driver loading stats at driver unloading Bug: 138963614 Test: opt-in to GameDriver or ANGLE and test Change-Id: I1e74cf55dd00f6fd7cb65d278d4dbaf018c5f322 --- libs/graphicsenv/GraphicsEnv.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 3e29e88b20..705a0a4b03 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -213,7 +213,8 @@ void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { case GpuStatsInfo::Driver::GL: case GpuStatsInfo::Driver::GL_UPDATED: case GpuStatsInfo::Driver::ANGLE: { - if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE) { + if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE || + mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) { mGpuStats.glDriverToLoad = driver; break; } @@ -225,7 +226,8 @@ void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { } case GpuStatsInfo::Driver::VULKAN: case GpuStatsInfo::Driver::VULKAN_UPDATED: { - if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE) { + if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE || + mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::VULKAN) { mGpuStats.vkDriverToLoad = driver; break; } -- cgit v1.2.3-59-g8ed1b From 6740e66bd1dd14c09804d56fbf859b64ae19fa84 Mon Sep 17 00:00:00 2001 From: Atif Niyaz Date: Wed, 7 Aug 2019 10:54:29 -0700 Subject: Add sleep to ShouldReportStats Test in libinput_tests Tests were flaky previously, by adding this sleep, this should should assert that stats.shouldReport() is always true. Test: atest LatencyStatisticsTest Bug: 139050511 Change-Id: I9ca106fca758378eded19c6bf130aaee5387967c Signed-off-by: Atif Niyaz --- libs/input/tests/LatencyStatistics_test.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libs') diff --git a/libs/input/tests/LatencyStatistics_test.cpp b/libs/input/tests/LatencyStatistics_test.cpp index 6d1cab4187..eb12d4ef6f 100644 --- a/libs/input/tests/LatencyStatistics_test.cpp +++ b/libs/input/tests/LatencyStatistics_test.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace android { namespace test { @@ -65,6 +66,8 @@ TEST(LatencyStatisticsTest, ShouldReportStats) { LatencyStatistics stats{0min}; stats.addValue(5.0); + std::this_thread::sleep_for(1us); + ASSERT_EQ(stats.shouldReport(), true); } -- cgit v1.2.3-59-g8ed1b From 282f1d7eb2ea7346be5ffb266b24746dfb7b3c46 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 24 Jul 2019 18:05:56 -0700 Subject: SurfaceFlinger: prevent division by 0 in Layer::fillInputInfo Check if scale is 0 before trying to apply it on the window scale. Bug: 137560795 Test: Set Window Scale Animation to off from developer options menu Change-Id: I7ae84e2838b1562ff62cdd94484bedba954e1f33 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 13 +++++++++++++ services/surfaceflinger/Layer.cpp | 17 +++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'libs') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index ff1ba0ad17..386f731d23 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -410,6 +410,19 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) { bgSurface->expectTap(1, 1); } +TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { + std::unique_ptr fgSurface = makeSurface(100, 100); + // In case we pass the very big inset without any checking. + fgSurface->mInputInfo.surfaceInset = INT32_MAX; + fgSurface->showAt(100, 100); + + fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); + + // expect no crash for overflow, and inset size to be clamped to surface size + injectTap(202, 202); + fgSurface->expectTap(1, 1); +} + // Ensure we ignore transparent region when getting screen bounds when positioning input frame. TEST_F(InputSurfacesTest, input_ignores_transparent_region) { std::unique_ptr surface = makeSurface(100, 100); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0bb08d9a89..e7fbfe936d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1975,14 +1975,14 @@ InputWindowInfo Layer::fillInputInfo() { ui::Transform t = getTransform(); const float xScale = t.sx(); const float yScale = t.sy(); - float xSurfaceInset = info.surfaceInset; - float ySurfaceInset = info.surfaceInset; + int32_t xSurfaceInset = info.surfaceInset; + int32_t ySurfaceInset = info.surfaceInset; if (xScale != 1.0f || yScale != 1.0f) { - info.windowXScale *= 1.0f / xScale; - info.windowYScale *= 1.0f / yScale; + info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f; + info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f; info.touchableRegion.scaleSelf(xScale, yScale); - xSurfaceInset *= xScale; - ySurfaceInset *= yScale; + xSurfaceInset = std::round(xSurfaceInset * xScale); + ySurfaceInset = std::round(ySurfaceInset * yScale); } // Transform layer size to screen space and inset it by surface insets. @@ -1994,6 +1994,11 @@ InputWindowInfo Layer::fillInputInfo() { layerBounds = getCroppedBufferSize(getDrawingState()); } layerBounds = t.transform(layerBounds); + + // clamp inset to layer bounds + xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0; + ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0; + layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset); // Input coordinate should match the layer bounds. -- cgit v1.2.3-59-g8ed1b From 01a5613bdae45087cff5473671d174d067519a0b Mon Sep 17 00:00:00 2001 From: Garfield Tan Date: Mon, 5 Aug 2019 16:44:21 -0700 Subject: Add metadata for mouse cursor. Mouse cursor metadata is stored in a parcel with a int32_t for mouse cursor type, and two floats for mouse hotspotX/Y. Therefore move the parcel to byte vector conversion into SurfaceComposerClient. If anyone needs to store metadata in raw byte vector we can change the interface later. Bug: 130822623 Test: SurfaceFlinger can get cursor type and hotspot. Change-Id: Ia7e0c952fcaefd14280322d9b2269f4dba38e8da --- libs/gui/SurfaceComposerClient.cpp | 5 +++-- libs/gui/include/gui/LayerMetadata.h | 7 ++++++- libs/gui/include/gui/SurfaceComposerClient.h | 3 +-- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e6b1beb2c4..40621e3ca6 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -795,14 +795,15 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMetadata( - const sp& sc, uint32_t key, std::vector data) { + const sp& sc, uint32_t key, const Parcel& p) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eMetadataChanged; - s->metadata.mMap[key] = std::move(data); + + s->metadata.mMap[key] = {p.data(), p.data() + p.dataSize()}; registerSurfaceControlForCallback(sc); return *this; diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index 47f0cede3a..d58e019799 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -22,7 +22,12 @@ namespace android { -enum { METADATA_OWNER_UID = 1, METADATA_WINDOW_TYPE = 2, METADATA_TASK_ID = 3 }; +enum { + METADATA_OWNER_UID = 1, + METADATA_WINDOW_TYPE = 2, + METADATA_TASK_ID = 3, + METADATA_MOUSE_CURSOR = 4, +}; struct LayerMetadata : public Parcelable { std::unordered_map> mMap; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 22ab62da44..f303a03254 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -379,8 +379,7 @@ public: Transaction& setCrop_legacy(const sp& sc, const Rect& crop); Transaction& setCornerRadius(const sp& sc, float cornerRadius); Transaction& setLayerStack(const sp& sc, uint32_t layerStack); - Transaction& setMetadata(const sp& sc, uint32_t key, - std::vector data); + Transaction& setMetadata(const sp& sc, uint32_t key, const Parcel& p); // Defers applying any changes made in this transaction until the Layer // identified by handle reaches the given frameNumber. If the Layer identified // by handle is removed, then we will apply this transaction regardless of -- cgit v1.2.3-59-g8ed1b From 2ccbe3a0359a1bd59d282400351f2e604d5aabb9 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Fri, 9 Aug 2019 14:35:36 -0700 Subject: InputTransport: store fd in a unique_fd. Use unique_fd to hold the file descriptor, so that it gets protected from being closed by someone else by fdsan. Test: atest libinput_tests inputflinger_tests Change-Id: I08df199294f9ddd7646c7bcd637b9c035e3c1e12 --- include/input/InputTransport.h | 14 +++--- libs/input/IInputFlinger.cpp | 6 +-- libs/input/InputTransport.cpp | 88 +++++++++++++++++----------------- libs/input/tests/InputChannel_test.cpp | 27 +++++++---- 4 files changed, 70 insertions(+), 65 deletions(-) (limited to 'libs') diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 690e0a11c8..28b8d80074 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -42,6 +42,8 @@ #include #include +#include + namespace android { class Parcel; @@ -166,8 +168,7 @@ protected: virtual ~InputChannel(); public: - InputChannel() = default; - InputChannel(const std::string& name, int fd); + static sp create(const std::string& name, android::base::unique_fd fd); /* Creates a pair of input channels. * @@ -177,7 +178,7 @@ public: sp& outServerChannel, sp& outClientChannel); inline std::string getName() const { return mName; } - inline int getFd() const { return mFd; } + inline int getFd() const { return mFd.get(); } /* Sends a message to the other endpoint. * @@ -208,16 +209,15 @@ public: sp dup() const; status_t write(Parcel& out) const; - status_t read(const Parcel& from); + static sp read(const Parcel& from); sp getToken() const; void setToken(const sp& token); private: - void setFd(int fd); - + InputChannel(const std::string& name, android::base::unique_fd fd); std::string mName; - int mFd = -1; + android::base::unique_fd mFd; sp mToken = nullptr; }; diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp index d6a73bfd27..90f6e09a69 100644 --- a/libs/input/IInputFlinger.cpp +++ b/libs/input/IInputFlinger.cpp @@ -92,15 +92,13 @@ status_t BnInputFlinger::onTransact( } case REGISTER_INPUT_CHANNEL_TRANSACTION: { CHECK_INTERFACE(IInputFlinger, data, reply); - sp channel = new InputChannel(); - channel->read(data); + sp channel = InputChannel::read(data); registerInputChannel(channel); break; } case UNREGISTER_INPUT_CHANNEL_TRANSACTION: { CHECK_INTERFACE(IInputFlinger, data, reply); - sp channel = new InputChannel(); - channel->read(data); + sp channel = InputChannel::read(data); unregisterInputChannel(channel); break; } diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 2ff301e270..7835651f11 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -227,35 +227,28 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const { // --- InputChannel --- -InputChannel::InputChannel(const std::string& name, int fd) : - mName(name) { +sp InputChannel::create(const std::string& name, android::base::unique_fd fd) { + const int result = fcntl(fd, F_SETFL, O_NONBLOCK); + if (result != 0) { + LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(), + strerror(errno)); + return nullptr; + } + return new InputChannel(name, std::move(fd)); +} + +InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd) + : mName(name), mFd(std::move(fd)) { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel constructed: name='%s', fd=%d", mName.c_str(), fd); #endif - - setFd(fd); } InputChannel::~InputChannel() { #if DEBUG_CHANNEL_LIFECYCLE - ALOGD("Input channel destroyed: name='%s', fd=%d", - mName.c_str(), mFd); + ALOGD("Input channel destroyed: name='%s', fd=%d", mName.c_str(), mFd.get()); #endif - - ::close(mFd); -} - -void InputChannel::setFd(int fd) { - if (mFd > 0) { - ::close(mFd); - } - mFd = fd; - if (mFd > 0) { - int result = fcntl(mFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " - "non-blocking. errno=%d", mName.c_str(), errno); - } } status_t InputChannel::openInputChannelPair(const std::string& name, @@ -276,13 +269,13 @@ status_t InputChannel::openInputChannelPair(const std::string& name, setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - std::string serverChannelName = name; - serverChannelName += " (server)"; - outServerChannel = new InputChannel(serverChannelName, sockets[0]); + std::string serverChannelName = name + " (server)"; + android::base::unique_fd serverFd(sockets[0]); + outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd)); - std::string clientChannelName = name; - clientChannelName += " (client)"; - outClientChannel = new InputChannel(clientChannelName, sockets[1]); + std::string clientChannelName = name + " (client)"; + android::base::unique_fd clientFd(sockets[1]); + outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd)); return OK; } @@ -292,7 +285,7 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { msg->getSanitizedCopy(&cleanMsg); ssize_t nWrite; do { - nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); + nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); if (nWrite < 0) { @@ -327,7 +320,7 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { status_t InputChannel::receiveMessage(InputMessage* msg) { ssize_t nRead; do { - nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT); + nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT); } while (nRead == -1 && errno == EINTR); if (nRead < 0) { @@ -365,39 +358,44 @@ status_t InputChannel::receiveMessage(InputMessage* msg) { } sp InputChannel::dup() const { - int fd = ::dup(getFd()); - return fd >= 0 ? new InputChannel(getName(), fd) : nullptr; + android::base::unique_fd newFd(::dup(getFd())); + if (!newFd.ok()) { + ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), mName.c_str(), + strerror(errno)); + return nullptr; + } + return InputChannel::create(mName, std::move(newFd)); } - status_t InputChannel::write(Parcel& out) const { - status_t s = out.writeString8(String8(getName().c_str())); - + status_t s = out.writeCString(getName().c_str()); if (s != OK) { return s; } + s = out.writeStrongBinder(mToken); if (s != OK) { return s; } - s = out.writeDupFileDescriptor(getFd()); - + s = out.writeUniqueFileDescriptor(mFd); return s; } -status_t InputChannel::read(const Parcel& from) { - mName = from.readString8(); - mToken = from.readStrongBinder(); - - int rawFd = from.readFileDescriptor(); - setFd(::dup(rawFd)); - - if (mFd < 0) { - return BAD_VALUE; +sp InputChannel::read(const Parcel& from) { + std::string name = from.readCString(); + sp token = from.readStrongBinder(); + android::base::unique_fd rawFd; + status_t fdResult = from.readUniqueFileDescriptor(&rawFd); + if (fdResult != OK) { + return nullptr; } - return OK; + sp channel = InputChannel::create(name, std::move(rawFd)); + if (channel != nullptr) { + channel->setToken(token); + } + return channel; } sp InputChannel::getToken() const { diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp index f1675c0d36..af74edd65d 100644 --- a/libs/input/tests/InputChannel_test.cpp +++ b/libs/input/tests/InputChannel_test.cpp @@ -22,11 +22,12 @@ #include #include +#include #include #include -#include #include #include +#include namespace android { @@ -43,20 +44,28 @@ TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptor // of a pipe and to check for EPIPE on the other end after the channel is destroyed. Pipe pipe; - sp inputChannel = new InputChannel("channel name", pipe.sendFd); + android::base::unique_fd sendFd(pipe.sendFd); + + sp inputChannel = InputChannel::create("channel name", std::move(sendFd)); + EXPECT_NE(inputChannel, nullptr) << "channel should be successfully created"; EXPECT_STREQ("channel name", inputChannel->getName().c_str()) << "channel should have provided name"; - EXPECT_EQ(pipe.sendFd, inputChannel->getFd()) - << "channel should have provided fd"; + EXPECT_NE(-1, inputChannel->getFd()) << "channel should have valid fd"; - inputChannel.clear(); // destroys input channel + // InputChannel should be the owner of the file descriptor now + ASSERT_FALSE(sendFd.ok()); +} - EXPECT_EQ(-EPIPE, pipe.readSignal()) - << "channel should have closed fd when destroyed"; +TEST_F(InputChannelTest, SetAndGetToken) { + Pipe pipe; + sp channel = + InputChannel::create("test channel", android::base::unique_fd(pipe.sendFd)); + EXPECT_EQ(channel->getToken(), nullptr); - // clean up fds of Pipe endpoints that were closed so we don't try to close them again - pipe.sendFd = -1; + sp token = new BBinder(); + channel->setToken(token); + EXPECT_EQ(token, channel->getToken()); } TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) { -- cgit v1.2.3-59-g8ed1b From 87c8ba767a25a4ee054d6c274405de89aae968c4 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Thu, 20 Jun 2019 14:20:52 -0700 Subject: gralloc: add IAllocator/IMapper 4.0 to frameworks/native Add support for gralloc 4.0 to the framework. Bug: 136016160 Test: Compiles and boots Change-Id: I26408e984308fa557e102efabb60302907310308 --- libs/ui/Android.bp | 3 + libs/ui/Gralloc4.cpp | 405 +++++++++++++++++++++++ libs/ui/GraphicBufferAllocator.cpp | 20 +- libs/ui/GraphicBufferMapper.cpp | 22 +- libs/ui/include/ui/Gralloc4.h | 95 ++++++ libs/ui/include/ui/GraphicBufferMapper.h | 1 + services/surfaceflinger/tests/fakehwc/Android.bp | 1 + services/vr/hardware_composer/Android.bp | 1 + 8 files changed, 535 insertions(+), 13 deletions(-) create mode 100644 libs/ui/Gralloc4.cpp create mode 100644 libs/ui/include/ui/Gralloc4.h (limited to 'libs') diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 2bbb0ee50a..8462fe7584 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -65,6 +65,7 @@ cc_library_shared { "Gralloc.cpp", "Gralloc2.cpp", "Gralloc3.cpp", + "Gralloc4.cpp", "GraphicBuffer.cpp", "GraphicBufferAllocator.cpp", "GraphicBufferMapper.cpp", @@ -89,10 +90,12 @@ cc_library_shared { "android.frameworks.bufferhub@1.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.common@1.2", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "libbase", "libcutils", "libhidlbase", diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp new file mode 100644 index 0000000000..dc105c095c --- /dev/null +++ b/libs/ui/Gralloc4.cpp @@ -0,0 +1,405 @@ +/* + * Copyright 2019 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 "Gralloc4" + +#include +#include +#include + +#include +#include +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wzero-length-array" +#include +#pragma clang diagnostic pop + +using android::hardware::graphics::allocator::V4_0::IAllocator; +using android::hardware::graphics::common::V1_2::BufferUsage; +using android::hardware::graphics::mapper::V4_0::BufferDescriptor; +using android::hardware::graphics::mapper::V4_0::Error; +using android::hardware::graphics::mapper::V4_0::IMapper; +using android::hardware::graphics::mapper::V4_0::YCbCrLayout; + +namespace android { + +namespace { + +static constexpr Error kTransactionError = Error::NO_RESOURCES; + +uint64_t getValidUsageBits() { + static const uint64_t validUsageBits = []() -> uint64_t { + uint64_t bits = 0; + for (const auto bit : + hardware::hidl_enum_range()) { + bits = bits | bit; + } + return bits; + }(); + return validUsageBits; +} + +static inline IMapper::Rect sGralloc4Rect(const Rect& rect) { + IMapper::Rect outRect{}; + outRect.left = rect.left; + outRect.top = rect.top; + outRect.width = rect.width(); + outRect.height = rect.height(); + return outRect; +} +static inline void sBufferDescriptorInfo(uint32_t width, uint32_t height, + android::PixelFormat format, uint32_t layerCount, + uint64_t usage, + IMapper::BufferDescriptorInfo* outDescriptorInfo) { + outDescriptorInfo->width = width; + outDescriptorInfo->height = height; + outDescriptorInfo->layerCount = layerCount; + outDescriptorInfo->format = static_cast(format); + outDescriptorInfo->usage = usage; +} + +} // anonymous namespace + +void Gralloc4Mapper::preload() { + android::hardware::preloadPassthroughService(); +} + +Gralloc4Mapper::Gralloc4Mapper() { + mMapper = IMapper::getService(); + if (mMapper == nullptr) { + ALOGI("mapper 4.x is not supported"); + return; + } + if (mMapper->isRemote()) { + LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode"); + } +} + +bool Gralloc4Mapper::isLoaded() const { + return mMapper != nullptr; +} + +status_t Gralloc4Mapper::validateBufferDescriptorInfo( + IMapper::BufferDescriptorInfo* descriptorInfo) const { + uint64_t validUsageBits = getValidUsageBits(); + + if (descriptorInfo->usage & ~validUsageBits) { + ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64, + descriptorInfo->usage & ~validUsageBits); + return BAD_VALUE; + } + return NO_ERROR; +} + +status_t Gralloc4Mapper::createDescriptor(void* bufferDescriptorInfo, + void* outBufferDescriptor) const { + IMapper::BufferDescriptorInfo* descriptorInfo = + static_cast(bufferDescriptorInfo); + BufferDescriptor* outDescriptor = static_cast(outBufferDescriptor); + + status_t status = validateBufferDescriptorInfo(descriptorInfo); + if (status != NO_ERROR) { + return status; + } + + Error error; + auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) { + error = tmpError; + if (error != Error::NONE) { + return; + } + *outDescriptor = tmpDescriptor; + }; + + hardware::Return ret = mMapper->createDescriptor(*descriptorInfo, hidl_cb); + + return static_cast((ret.isOk()) ? error : kTransactionError); +} + +status_t Gralloc4Mapper::importBuffer(const hardware::hidl_handle& rawHandle, + buffer_handle_t* outBufferHandle) const { + Error error; + auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) { + error = tmpError; + if (error != Error::NONE) { + return; + } + *outBufferHandle = static_cast(tmpBuffer); + }); + + return static_cast((ret.isOk()) ? error : kTransactionError); +} + +void Gralloc4Mapper::freeBuffer(buffer_handle_t bufferHandle) const { + auto buffer = const_cast(bufferHandle); + auto ret = mMapper->freeBuffer(buffer); + + auto error = (ret.isOk()) ? static_cast(ret) : kTransactionError; + ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error); +} + +status_t Gralloc4Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, + uint32_t height, android::PixelFormat format, + uint32_t layerCount, uint64_t usage, + uint32_t stride) const { + IMapper::BufferDescriptorInfo descriptorInfo; + sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo); + + auto buffer = const_cast(bufferHandle); + auto ret = mMapper->validateBufferSize(buffer, descriptorInfo, stride); + + return static_cast((ret.isOk()) ? static_cast(ret) : kTransactionError); +} + +void Gralloc4Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts) const { + *outNumFds = uint32_t(bufferHandle->numFds); + *outNumInts = uint32_t(bufferHandle->numInts); + + Error error; + auto buffer = const_cast(bufferHandle); + auto ret = mMapper->getTransportSize(buffer, + [&](const auto& tmpError, const auto& tmpNumFds, + const auto& tmpNumInts) { + error = tmpError; + if (error != Error::NONE) { + return; + } + *outNumFds = tmpNumFds; + *outNumInts = tmpNumInts; + }); + + error = (ret.isOk()) ? error : kTransactionError; + + ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error); +} + +status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds, + int acquireFence, void** outData, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride) const { + auto buffer = const_cast(bufferHandle); + + IMapper::Rect accessRegion = sGralloc4Rect(bounds); + + // put acquireFence in a hidl_handle + hardware::hidl_handle acquireFenceHandle; + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + Error error; + auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpData, + const auto& tmpBytesPerPixel, const auto& tmpBytesPerStride) { + error = tmpError; + if (error != Error::NONE) { + return; + } + *outData = tmpData; + if (outBytesPerPixel) { + *outBytesPerPixel = tmpBytesPerPixel; + } + if (outBytesPerStride) { + *outBytesPerStride = tmpBytesPerStride; + } + }); + + // we own acquireFence even on errors + if (acquireFence >= 0) { + close(acquireFence); + } + + error = (ret.isOk()) ? error : kTransactionError; + + ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error); + + return static_cast(error); +} + +status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds, + int acquireFence, android_ycbcr* ycbcr) const { + auto buffer = const_cast(bufferHandle); + + IMapper::Rect accessRegion = sGralloc4Rect(bounds); + + // put acquireFence in a hidl_handle + hardware::hidl_handle acquireFenceHandle; + NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0); + if (acquireFence >= 0) { + auto h = native_handle_init(acquireFenceStorage, 1, 0); + h->data[0] = acquireFence; + acquireFenceHandle = h; + } + + YCbCrLayout layout; + Error error; + auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle, + [&](const auto& tmpError, const auto& tmpLayout) { + error = tmpError; + if (error != Error::NONE) { + return; + } + + layout = tmpLayout; + }); + + if (error == Error::NONE) { + ycbcr->y = layout.y; + ycbcr->cb = layout.cb; + ycbcr->cr = layout.cr; + ycbcr->ystride = static_cast(layout.yStride); + ycbcr->cstride = static_cast(layout.cStride); + ycbcr->chroma_step = static_cast(layout.chromaStep); + } + + // we own acquireFence even on errors + if (acquireFence >= 0) { + close(acquireFence); + } + + return static_cast((ret.isOk()) ? error : kTransactionError); +} + +int Gralloc4Mapper::unlock(buffer_handle_t bufferHandle) const { + auto buffer = const_cast(bufferHandle); + + int releaseFence = -1; + Error error; + auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) { + error = tmpError; + if (error != Error::NONE) { + return; + } + + auto fenceHandle = tmpReleaseFence.getNativeHandle(); + if (fenceHandle && fenceHandle->numFds == 1) { + int fd = dup(fenceHandle->data[0]); + if (fd >= 0) { + releaseFence = fd; + } else { + ALOGD("failed to dup unlock release fence"); + sync_wait(fenceHandle->data[0], -1); + } + } + }); + + if (!ret.isOk()) { + error = kTransactionError; + } + + if (error != Error::NONE) { + ALOGE("unlock(%p) failed with %d", buffer, error); + } + + return releaseFence; +} + +status_t Gralloc4Mapper::isSupported(uint32_t width, uint32_t height, android::PixelFormat format, + uint32_t layerCount, uint64_t usage, + bool* outSupported) const { + IMapper::BufferDescriptorInfo descriptorInfo; + sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo); + + Error error; + auto ret = mMapper->isSupported(descriptorInfo, + [&](const auto& tmpError, const auto& tmpSupported) { + error = tmpError; + if (error != Error::NONE) { + return; + } + if (outSupported) { + *outSupported = tmpSupported; + } + }); + + if (!ret.isOk()) { + error = kTransactionError; + } + + if (error != Error::NONE) { + ALOGE("isSupported(%u, %u, %d, %u, ...) failed with %d", width, height, format, layerCount, + error); + } + + return static_cast(error); +} + +Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) { + mAllocator = IAllocator::getService(); + if (mAllocator == nullptr) { + ALOGW("allocator 3.x is not supported"); + return; + } +} + +bool Gralloc4Allocator::isLoaded() const { + return mAllocator != nullptr; +} + +std::string Gralloc4Allocator::dumpDebugInfo() const { + std::string debugInfo; + + mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); }); + + return debugInfo; +} + +status_t Gralloc4Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format, + uint32_t layerCount, uint64_t usage, uint32_t bufferCount, + uint32_t* outStride, buffer_handle_t* outBufferHandles) const { + IMapper::BufferDescriptorInfo descriptorInfo; + sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo); + + BufferDescriptor descriptor; + status_t error = mMapper.createDescriptor(static_cast(&descriptorInfo), + static_cast(&descriptor)); + if (error != NO_ERROR) { + return error; + } + + auto ret = mAllocator->allocate(descriptor, bufferCount, + [&](const auto& tmpError, const auto& tmpStride, + const auto& tmpBuffers) { + error = static_cast(tmpError); + if (tmpError != Error::NONE) { + return; + } + + // import buffers + for (uint32_t i = 0; i < bufferCount; i++) { + error = mMapper.importBuffer(tmpBuffers[i], + &outBufferHandles[i]); + if (error != NO_ERROR) { + for (uint32_t j = 0; j < i; j++) { + mMapper.freeBuffer(outBufferHandles[j]); + outBufferHandles[j] = nullptr; + } + return; + } + } + *outStride = tmpStride; + }); + + // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now + hardware::IPCThreadState::self()->flushCommands(); + + return (ret.isOk()) ? error : static_cast(kTransactionError); +} + +} // namespace android diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index 9c7d1fda90..eb787a2e40 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include namespace android { @@ -47,16 +48,23 @@ KeyedVector GraphicBufferAllocator::sAllocList; GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) { + mAllocator = std::make_unique( + reinterpret_cast(mMapper.getGrallocMapper())); + if (mAllocator->isLoaded()) { + return; + } mAllocator = std::make_unique( reinterpret_cast(mMapper.getGrallocMapper())); - if (!mAllocator->isLoaded()) { - mAllocator = std::make_unique( - reinterpret_cast(mMapper.getGrallocMapper())); + if (mAllocator->isLoaded()) { + return; } - - if (!mAllocator->isLoaded()) { - LOG_ALWAYS_FATAL("gralloc-allocator is missing"); + mAllocator = std::make_unique( + reinterpret_cast(mMapper.getGrallocMapper())); + if (mAllocator->isLoaded()) { + return; } + + LOG_ALWAYS_FATAL("gralloc-allocator is missing"); } GraphicBufferAllocator::~GraphicBufferAllocator() {} diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index 25b7247b1b..4d087d151c 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -47,20 +48,27 @@ ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper ) void GraphicBufferMapper::preloadHal() { Gralloc2Mapper::preload(); Gralloc3Mapper::preload(); + Gralloc4Mapper::preload(); } GraphicBufferMapper::GraphicBufferMapper() { + mMapper = std::make_unique(); + if (mMapper->isLoaded()) { + mMapperVersion = Version::GRALLOC_4; + return; + } mMapper = std::make_unique(); - if (!mMapper->isLoaded()) { - mMapper = std::make_unique(); - mMapperVersion = Version::GRALLOC_2; - } else { + if (mMapper->isLoaded()) { mMapperVersion = Version::GRALLOC_3; + return; } - - if (!mMapper->isLoaded()) { - LOG_ALWAYS_FATAL("gralloc-mapper is missing"); + mMapper = std::make_unique(); + if (mMapper->isLoaded()) { + mMapperVersion = Version::GRALLOC_2; + return; } + + LOG_ALWAYS_FATAL("gralloc-mapper is missing"); } status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle, diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h new file mode 100644 index 0000000000..14b65bc220 --- /dev/null +++ b/libs/ui/include/ui/Gralloc4.h @@ -0,0 +1,95 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_UI_GRALLOC4_H +#define ANDROID_UI_GRALLOC4_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +class Gralloc4Mapper : public GrallocMapper { +public: + static void preload(); + + Gralloc4Mapper(); + + bool isLoaded() const override; + + status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override; + + status_t importBuffer(const hardware::hidl_handle& rawHandle, + buffer_handle_t* outBufferHandle) const override; + + void freeBuffer(buffer_handle_t bufferHandle) const override; + + status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height, + android::PixelFormat format, uint32_t layerCount, uint64_t usage, + uint32_t stride) const override; + + void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds, + uint32_t* outNumInts) const override; + + status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds, + int acquireFence, void** outData, int32_t* outBytesPerPixel, + int32_t* outBytesPerStride) const override; + + status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds, + int acquireFence, android_ycbcr* ycbcr) const override; + + int unlock(buffer_handle_t bufferHandle) const override; + + status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format, + uint32_t layerCount, uint64_t usage, bool* outSupported) const override; + +private: + // Determines whether the passed info is compatible with the mapper. + status_t validateBufferDescriptorInfo( + hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo* descriptorInfo) const; + + sp mMapper; +}; + +class Gralloc4Allocator : public GrallocAllocator { +public: + // An allocator relies on a mapper, and that mapper must be alive at all + // time. + Gralloc4Allocator(const Gralloc4Mapper& mapper); + + bool isLoaded() const override; + + std::string dumpDebugInfo() const override; + + status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, + uint64_t usage, uint32_t bufferCount, uint32_t* outStride, + buffer_handle_t* outBufferHandles) const override; + +private: + const Gralloc4Mapper& mMapper; + sp mAllocator; +}; + +} // namespace android + +#endif // ANDROID_UI_GRALLOC4_H diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h index 24614549be..c401a4863c 100644 --- a/libs/ui/include/ui/GraphicBufferMapper.h +++ b/libs/ui/include/ui/GraphicBufferMapper.h @@ -44,6 +44,7 @@ public: enum Version { GRALLOC_2, GRALLOC_3, + GRALLOC_4, }; static void preloadHal(); static inline GraphicBufferMapper& get() { return getInstance(); } diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp index f359550bfb..644cd7e698 100644 --- a/services/surfaceflinger/tests/fakehwc/Android.bp +++ b/services/surfaceflinger/tests/fakehwc/Android.bp @@ -13,6 +13,7 @@ cc_test { "android.hardware.graphics.composer@2.1-resources", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "android.hardware.power@1.3", "libbase", "libbinder", diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index bc7cc1c409..0e5faf4058 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -17,6 +17,7 @@ cc_library_shared { "android.hardware.graphics.composer@2.1-resources", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", + "android.hardware.graphics.mapper@4.0", "libbase", "libbufferhubqueue", "libbinder", -- cgit v1.2.3-59-g8ed1b From 82c7531ebcdf6afca4ef08b4e7227b2cebb38cd1 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 24 Jul 2019 15:18:30 +0200 Subject: Reject invalid object types for incoming transactions. TYPE_PTR and TYPE_FDA should only be used for scatter-gather transactions, which is not supported by libbinder. Because userspace is responsible for cleaning up the transaction objects, we can't just reject the transaction outright; instead, free the objects and make sure the Parcel won't contain them going forward. While we're at it, also reject weak binders now, since those are no longer supported. For Parcels which were expecting valid objects, those will now fail to unparcel, and return an error to the caller, which seems reasonable. For Parcels which didn't expect any objects, the Parcel will be read out successfully, but also no harm should be done, as there's no way to propagate the bad objects. Bug: 135930648 Test: atest binderLibTest Change-Id: I2a4b408d6dcf1a67f3093d40061cb6159a0444f9 --- libs/binder/Parcel.cpp | 16 ++++++++++++++++ libs/binder/tests/binderLibTest.cpp | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'libs') diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index ed6c834af8..3a7a7a9c3f 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2354,6 +2354,22 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, mObjectsSize = 0; break; } + const flat_binder_object* flat + = reinterpret_cast(mData + offset); + uint32_t type = flat->hdr.type; + if (!(type == BINDER_TYPE_BINDER || type == BINDER_TYPE_HANDLE || + type == BINDER_TYPE_FD)) { + // We should never receive other types (eg BINDER_TYPE_FDA) as long as we don't support + // them in libbinder. If we do receive them, it probably means a kernel bug; try to + // recover gracefully by clearing out the objects, and releasing the objects we do + // know about. + android_errorWriteLog(0x534e4554, "135930648"); + ALOGE("%s: unsupported type object (%" PRIu32 ") at offset %" PRIu64 "\n", + __func__, type, (uint64_t)offset); + releaseObjects(); + mObjectsSize = 0; + break; + } minOffset = offset + sizeof(flat_binder_object); } scanForFds(); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 495b2f9d9a..5c6cf9db64 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -72,6 +72,7 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, BINDER_LIB_TEST_ECHO_VECTOR, + BINDER_LIB_TEST_REJECT_BUF, }; pid_t start_server_process(int arg2, bool usePoll = false) @@ -1024,6 +1025,34 @@ TEST_F(BinderLibTest, VectorSent) { EXPECT_EQ(readValue, testValue); } +TEST_F(BinderLibTest, BufRejected) { + Parcel data, reply; + uint32_t buf; + sp server = addServer(); + ASSERT_TRUE(server != nullptr); + + binder_buffer_object obj { + .hdr = { .type = BINDER_TYPE_PTR }, + .buffer = reinterpret_cast((void*)&buf), + .length = 4, + .flags = 0, + }; + data.setDataCapacity(1024); + // Write a bogus object at offset 0 to get an entry in the offset table + data.writeFileDescriptor(0); + EXPECT_EQ(data.objectsCount(), 1); + uint8_t *parcelData = const_cast(data.data()); + // And now, overwrite it with the buffer object + memcpy(parcelData, &obj, sizeof(obj)); + data.setDataSize(sizeof(obj)); + + status_t ret = server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply); + // Either the kernel should reject this transaction (if it's correct), but + // if it's not, the server implementation should return an error if it + // finds an object in the received Parcel. + EXPECT_NE(NO_ERROR, ret); +} + class BinderLibTestService : public BBinder { public: @@ -1306,6 +1335,9 @@ class BinderLibTestService : public BBinder reply->writeUint64Vector(vector); return NO_ERROR; } + case BINDER_LIB_TEST_REJECT_BUF: { + return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR; + } default: return UNKNOWN_TRANSACTION; }; @@ -1337,6 +1369,9 @@ int run_server(int index, int readypipefd, bool usePoll) */ testService->setExtension(new BBinder()); + // Required for test "BufRejected' + testService->setRequestingSid(true); + /* * We need this below, but can't hold a sp<> because it prevents the * node from being cleaned up automatically. It's safe in this case -- cgit v1.2.3-59-g8ed1b From 5de3ad2cee2b5a30ab442dcc202d0799c5b4ac23 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Tue, 20 Aug 2019 07:47:43 -0700 Subject: Switch from ITransactionCompletedListener to IBinder keys IBinder remains consistent across multiple transactions when passed cross-process to SF. However, interface_cast'ing it to an ITransactionCompletedListener results in different underlying objects. Switch to using IBinder as the keys for listener callbacks. Bug: 139731321 Test: build, boot, SurfaceFlinger_test Change-Id: I9bea76664087020eb43ceec258b5ecede0faaea5 --- libs/gui/ISurfaceComposer.cpp | 5 +-- libs/gui/ITransactionCompletedListener.cpp | 2 +- libs/gui/SurfaceComposerClient.cpp | 2 +- .../include/gui/ITransactionCompletedListener.h | 47 +++++++++++++++++--- services/surfaceflinger/SurfaceFlinger.h | 8 +--- .../surfaceflinger/TransactionCompletedThread.cpp | 28 +++++++----- .../surfaceflinger/TransactionCompletedThread.h | 51 ++++------------------ 7 files changed, 70 insertions(+), 73 deletions(-) (limited to 'libs') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 12deaf0bd6..dc161b7222 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -93,7 +93,7 @@ public: if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) { for (const auto& [listener, callbackIds] : listenerCallbacks) { - data.writeStrongBinder(IInterface::asBinder(listener)); + data.writeStrongBinder(listener); data.writeInt64Vector(callbackIds); } } @@ -1042,8 +1042,7 @@ status_t BnSurfaceComposer::onTransact( std::vector listenerCallbacks; int32_t listenersSize = data.readInt32(); for (int32_t i = 0; i < listenersSize; i++) { - auto listener = - interface_cast(data.readStrongBinder()); + auto listener = data.readStrongBinder(); std::vector callbackIds; data.readInt64Vector(&callbackIds); listenerCallbacks.emplace_back(listener, callbackIds); diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 74cd4f1ede..acda6001cc 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -151,7 +151,7 @@ status_t ListenerStats::readFromParcel(const Parcel* input) { return NO_ERROR; } -ListenerStats ListenerStats::createEmpty(const sp& listener, +ListenerStats ListenerStats::createEmpty(const sp& listener, const std::unordered_set& callbackIds) { ListenerStats listenerStats; listenerStats.listener = listener; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e6b1beb2c4..3d074e1ef4 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -548,7 +548,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { continue; } - listenerCallbacks.emplace_back(listener, std::move(callbackIds)); + listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds)); // If the listener has any SurfaceControls set on this Transaction update the surface state for (const auto& surfaceControl : surfaceControls) { diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index cbfd365692..178ca2d7e2 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -31,6 +31,7 @@ namespace android { class ITransactionCompletedListener; +class ListenerCallbacks; using CallbackId = int64_t; @@ -72,10 +73,10 @@ public: status_t writeToParcel(Parcel* output) const override; status_t readFromParcel(const Parcel* input) override; - static ListenerStats createEmpty(const sp& listener, + static ListenerStats createEmpty(const sp& listener, const std::unordered_set& callbackIds); - sp listener; + sp listener; std::vector transactionStats; }; @@ -97,13 +98,11 @@ public: class ListenerCallbacks { public: - ListenerCallbacks(const sp& listener, - const std::unordered_set& callbacks) + ListenerCallbacks(const sp& listener, const std::unordered_set& callbacks) : transactionCompletedListener(listener), callbackIds(callbacks.begin(), callbacks.end()) {} - ListenerCallbacks(const sp& listener, - const std::vector& ids) + ListenerCallbacks(const sp& listener, const std::vector& ids) : transactionCompletedListener(listener), callbackIds(ids) {} bool operator==(const ListenerCallbacks& rhs) const { @@ -116,8 +115,42 @@ public: return callbackIds.front() == rhs.callbackIds.front(); } - sp transactionCompletedListener; + sp transactionCompletedListener; std::vector callbackIds; }; +struct IListenerHash { + std::size_t operator()(const sp& strongPointer) const { + return std::hash{}(strongPointer.get()); + } +}; + +struct CallbackIdsHash { + // CallbackId vectors have several properties that let us get away with this simple hash. + // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is + // empty we can still hash 0. + // 2) CallbackId vectors for the same listener either are identical or contain none of the + // same members. It is sufficient to just check the first CallbackId in the vectors. If + // they match, they are the same. If they do not match, they are not the same. + std::size_t operator()(const std::vector& callbackIds) const { + return std::hash{}((callbackIds.empty()) ? 0 : callbackIds.front()); + } +}; + +struct ListenerCallbacksHash { + std::size_t HashCombine(size_t value1, size_t value2) const { + return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); + } + + std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { + struct IListenerHash listenerHasher; + struct CallbackIdsHash callbackIdsHasher; + + std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); + std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); + + return HashCombine(listenerHash, callbackIdsHash); + } +}; + } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e199ad55f8..5e263b2c9d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1025,11 +1026,6 @@ private: uint32_t mTexturePoolSize = 0; std::vector mTexturePool; - struct IBinderHash { - std::size_t operator()(const sp& strongPointer) const { - return std::hash{}(strongPointer.get()); - } - }; struct TransactionState { TransactionState(const Vector& composerStates, const Vector& displayStates, uint32_t transactionFlags, @@ -1054,7 +1050,7 @@ private: const int64_t postTime; bool privileged; }; - std::unordered_map, std::queue, IBinderHash> mTransactionQueues; + std::unordered_map, std::queue, IListenerHash> mTransactionQueues; /* ------------------------------------------------------------------------ * Feature prototyping diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp index c519f8d647..1324f20e1c 100644 --- a/services/surfaceflinger/TransactionCompletedThread.cpp +++ b/services/surfaceflinger/TransactionCompletedThread.cpp @@ -24,7 +24,6 @@ #include #include -#include #include namespace android { @@ -58,7 +57,7 @@ TransactionCompletedThread::~TransactionCompletedThread() { { std::lock_guard lock(mMutex); for (const auto& [listener, transactionStats] : mCompletedTransactions) { - IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient); + listener->unlinkToDeath(mDeathRecipient); } } } @@ -85,7 +84,7 @@ status_t TransactionCompletedThread::startRegistration(const ListenerCallbacks& auto& [listener, callbackIds] = listenerCallbacks; if (mCompletedTransactions.count(listener) == 0) { - status_t err = IInterface::asBinder(listener)->linkToDeath(mDeathRecipient); + status_t err = listener->linkToDeath(mDeathRecipient); if (err != NO_ERROR) { ALOGE("cannot add callback because linkToDeath failed, err: %d", err); return err; @@ -119,8 +118,7 @@ status_t TransactionCompletedThread::endRegistration(const ListenerCallbacks& li } bool TransactionCompletedThread::isRegisteringTransaction( - const sp& transactionListener, - const std::vector& callbackIds) { + const sp& transactionListener, const std::vector& callbackIds) { ListenerCallbacks listenerCallbacks(transactionListener, callbackIds); auto itr = mRegisteringTransactions.find(listenerCallbacks); @@ -201,8 +199,8 @@ status_t TransactionCompletedThread::registerUnpresentedCallbackHandle( } status_t TransactionCompletedThread::findTransactionStats( - const sp& listener, - const std::vector& callbackIds, TransactionStats** outTransactionStats) { + const sp& listener, const std::vector& callbackIds, + TransactionStats** outTransactionStats) { auto& transactionStatsDeque = mCompletedTransactions[listener]; // Search back to front because the most recent transactions are at the back of the deque @@ -300,10 +298,16 @@ void TransactionCompletedThread::threadMain() { // If the listener has completed transactions if (!listenerStats.transactionStats.empty()) { // If the listener is still alive - if (IInterface::asBinder(listener)->isBinderAlive()) { - // Send callback - listenerStats.listener->onTransactionCompleted(listenerStats); - IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient); + if (listener->isBinderAlive()) { + // Send callback. The listener stored in listenerStats + // comes from the cross-process setTransactionState call to + // SF. This MUST be an ITransactionCompletedListener. We + // keep it as an IBinder due to consistency reasons: if we + // interface_cast at the IPC boundary when reading a Parcel, + // we get pointers that compare unequal in the SF process. + interface_cast(listenerStats.listener) + ->onTransactionCompleted(listenerStats); + listener->unlinkToDeath(mDeathRecipient); } completedTransactionsItr = mCompletedTransactions.erase(completedTransactionsItr); } else { @@ -335,7 +339,7 @@ void TransactionCompletedThread::threadMain() { // ----------------------------------------------------------------------- -CallbackHandle::CallbackHandle(const sp& transactionListener, +CallbackHandle::CallbackHandle(const sp& transactionListener, const std::vector& ids, const sp& sc) : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {} diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h index e255e5090e..a85ad1e63c 100644 --- a/services/surfaceflinger/TransactionCompletedThread.h +++ b/services/surfaceflinger/TransactionCompletedThread.h @@ -31,46 +31,12 @@ namespace android { -struct ITransactionCompletedListenerHash { - std::size_t operator()(const sp& listener) const { - return std::hash{}((listener) ? IInterface::asBinder(listener).get() : nullptr); - } -}; - -struct CallbackIdsHash { - // CallbackId vectors have several properties that let us get away with this simple hash. - // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is - // empty we can still hash 0. - // 2) CallbackId vectors for the same listener either are identical or contain none of the - // same members. It is sufficient to just check the first CallbackId in the vectors. If - // they match, they are the same. If they do not match, they are not the same. - std::size_t operator()(const std::vector& callbackIds) const { - return std::hash{}((callbackIds.empty()) ? 0 : callbackIds.front()); - } -}; - -struct ListenerCallbacksHash { - std::size_t HashCombine(size_t value1, size_t value2) const { - return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); - } - - std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { - struct ITransactionCompletedListenerHash listenerHasher; - struct CallbackIdsHash callbackIdsHasher; - - std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); - std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); - - return HashCombine(listenerHash, callbackIdsHash); - } -}; - class CallbackHandle : public RefBase { public: - CallbackHandle(const sp& transactionListener, - const std::vector& ids, const sp& sc); + CallbackHandle(const sp& transactionListener, const std::vector& ids, + const sp& sc); - sp listener; + sp listener; std::vector callbackIds; wp surfaceControl; @@ -114,10 +80,10 @@ public: private: void threadMain(); - bool isRegisteringTransaction(const sp& transactionListener, + bool isRegisteringTransaction(const sp& transactionListener, const std::vector& callbackIds) REQUIRES(mMutex); - status_t findTransactionStats(const sp& listener, + status_t findTransactionStats(const sp& listener, const std::vector& callbackIds, TransactionStats** outTransactionStats) REQUIRES(mMutex); @@ -146,13 +112,12 @@ private: GUARDED_BY(mMutex); std::unordered_map< - sp, + sp, std::unordered_map, uint32_t /*count*/, CallbackIdsHash>, - ITransactionCompletedListenerHash> + IListenerHash> mPendingTransactions GUARDED_BY(mMutex); - std::unordered_map, std::deque, - ITransactionCompletedListenerHash> + std::unordered_map, std::deque, IListenerHash> mCompletedTransactions GUARDED_BY(mMutex); bool mRunning GUARDED_BY(mMutex) = false; -- cgit v1.2.3-59-g8ed1b From 9fa2cb6c5af15e5386c4632aed4847057c08340b Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 15 Jul 2019 17:36:26 -0700 Subject: [ANativeWindow] Add test infrastructure for apex apis * Add ANativeWindow_getLastDequeueDuration as proof of concept * Add ANativeWindowTest harness * apex/ include directory for code living in apex modules, so that vndk or system apis aren't pulled in * TEST_MAPPING configuration for presubmit Note that we're not piggybacking off of the existing Surface_test harness, as those tests assume that the libgui Surface is The ANativeWindow surface implementation, which means that those tests may test implementation details that the harness defined in this change should not attempt to test. Further, if an alternative implementation is provided (e.g. an ANativeWindow -> BLAST adapter), we should be able to parameterize the tests here. For now, however, we'll keep the assumption that Surface is the only relevant surface implementation so that nonzero tests may be written. Bug: 137012161 Bug: 137012798 Test: libnativewindow_test Change-Id: I0dddc348563ba95530fb1bd04bde66080755a91d --- libs/gui/TEST_MAPPING | 7 +++ libs/nativewindow/ANativeWindow.cpp | 8 +++ libs/nativewindow/TEST_MAPPING | 7 +++ libs/nativewindow/include/apex/window.h | 34 +++++++++++++ libs/nativewindow/include/system/window.h | 3 +- libs/nativewindow/libnativewindow.map.txt | 1 + libs/nativewindow/tests/ANativeWindowTest.cpp | 72 +++++++++++++++++++++++++++ libs/nativewindow/tests/Android.bp | 13 ++++- libs/nativewindow/tests/c_compatibility.c | 1 + 9 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 libs/gui/TEST_MAPPING create mode 100644 libs/nativewindow/TEST_MAPPING create mode 100644 libs/nativewindow/include/apex/window.h create mode 100644 libs/nativewindow/tests/ANativeWindowTest.cpp (limited to 'libs') diff --git a/libs/gui/TEST_MAPPING b/libs/gui/TEST_MAPPING new file mode 100644 index 0000000000..1c435304a8 --- /dev/null +++ b/libs/gui/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "imports": [ + { + "path": "frameworks/native/libs/nativewindow" + } + ] +} diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 1751443419..4c59e6ce98 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -266,3 +266,11 @@ int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) { int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) { return native_window_set_auto_prerotation(window, autoPrerotation); } + +/************************************************************************************************** + * apex-stable + **************************************************************************************************/ + +int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { + return query(window, NATIVE_WINDOW_LAST_DEQUEUE_DURATION); +} diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING new file mode 100644 index 0000000000..3d7f3c28f4 --- /dev/null +++ b/libs/nativewindow/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "libnativewindow_test" + } + ] +} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h new file mode 100644 index 0000000000..0260cbcfb4 --- /dev/null +++ b/libs/nativewindow/include/apex/window.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019 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 + +// apex is a superset of the NDK +#include + +__BEGIN_DECLS + +/** + * Retrieves how long it took for the last time a buffer was dequeued. + * + * \return a negative value on error, otherwise returns the duration in + * microseconds. + */ +int ANativeWindow_getLastDequeueDuration(ANativeWindow* window); + +__END_DECLS diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 8cbf0a4244..78354bba6b 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -41,7 +41,8 @@ #include #include -// system/window.h is a superset of the vndk +// system/window.h is a superset of the vndk and apex apis +#include #include diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 119a07dad7..7fe4df0606 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -22,6 +22,7 @@ LIBNATIVEWINDOW { ANativeWindow_getBuffersDataSpace; # introduced=28 ANativeWindow_getFormat; ANativeWindow_getHeight; + ANativeWindow_getLastDequeueDuration; # apex # introduced=30 ANativeWindow_getWidth; ANativeWindow_lock; ANativeWindow_query; # vndk diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp new file mode 100644 index 0000000000..a80da24a47 --- /dev/null +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -0,0 +1,72 @@ +/* + * Copyright 2019 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 "ANativeWindow_test" +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +// We need to use the private system apis since not everything is visible to +// apexes yet. +#include + +using namespace android; + +class ANativeWindowTest : public ::testing::Test { +protected: + void SetUp() override { + 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()); + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN); + mWindow = new Surface(mProducer); + const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU); + EXPECT_EQ(0, success); + } + + void TearDown() override { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGV("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + const int success = native_window_api_disconnect(mWindow.get(), NATIVE_WINDOW_API_CPU); + EXPECT_EQ(0, success); + } + sp mProducer; + sp mConsumer; + sp mItemConsumer; + sp mWindow; +}; + +TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) { + int result = ANativeWindow_getLastDequeueDuration(mWindow.get()); + EXPECT_EQ(0, result); +} + +TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { + ANativeWindowBuffer* buffer; + int fd; + int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, result); + + result = ANativeWindow_getLastDequeueDuration(mWindow.get()); + EXPECT_GT(result, 0); +} diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp index 20071be668..cdb3d2054f 100644 --- a/libs/nativewindow/tests/Android.bp +++ b/libs/nativewindow/tests/Android.bp @@ -15,13 +15,22 @@ // cc_test { - name: "AHardwareBufferTest", + name: "libnativewindow_test", + test_suites: [ + "device-tests", + ], shared_libs: [ + "libgui", + "liblog", "libnativewindow", + "libsync", + "libutils", "android.hardware.graphics.common@1.0", ], srcs: [ "AHardwareBufferTest.cpp", - "c_compatibility.c"], + "ANativeWindowTest.cpp", + "c_compatibility.c", + ], cflags: ["-Wall", "-Werror"], } diff --git a/libs/nativewindow/tests/c_compatibility.c b/libs/nativewindow/tests/c_compatibility.c index befd88fd07..aa9b4f7e78 100644 --- a/libs/nativewindow/tests/c_compatibility.c +++ b/libs/nativewindow/tests/c_compatibility.c @@ -16,6 +16,7 @@ #include #include +#include #include #include -- cgit v1.2.3-59-g8ed1b From 0ccfdc4f792a23458ae174ef9b1f5a3c071af74c Mon Sep 17 00:00:00 2001 From: Yi Kong Date: Mon, 19 Aug 2019 10:32:58 -0700 Subject: Remove -fwhole-program-vtables flags from librenderengine static library -fwhole-program-vtables optimisation is not possible for a static library, since at linking stage there are other parts that are not LTO'ed. Test: presubmit Change-Id: I64bccf091fa62d91ca8e3bb9aa0658a0c99ca2d7 --- libs/renderengine/Android.bp | 3 --- 1 file changed, 3 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index cc252d67ae..136ad0da62 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -71,9 +71,6 @@ cc_library_static { "-fvisibility=hidden", "-Werror=format", ], - cppflags: [ - "-fwhole-program-vtables", // requires ThinLTO - ], srcs: [ ":librenderengine_sources", ":librenderengine_gl_sources", -- cgit v1.2.3-59-g8ed1b From c185192c424b167587bfbb144d548c4d888a7156 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 21 Aug 2019 14:02:45 -0700 Subject: libgui: reset mEnableFrameTimestamps when Surface disconnects Bug: 134185757 Test: build, flash and boot Change-Id: Ibe2ae9636bd0bf2beb6ab9e3c6a9a81e3fc7442a --- libs/gui/Surface.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 4e6a4e7b4c..eb2e3f0615 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1354,6 +1354,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mTransform = 0; mStickyTransform = 0; mAutoPrerotation = false; + mEnableFrameTimestamps = false; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; -- cgit v1.2.3-59-g8ed1b From ee03b7874139801e1d94c433874fb114ea659767 Mon Sep 17 00:00:00 2001 From: Hui Yu Date: Thu, 22 Aug 2019 14:48:40 -0700 Subject: Add new parameter capability to onUidStateChanged() Bug: 136274596 Change-Id: Iadafc64cd580fa195786333485774e0951d3fd4b --- libs/binder/IUidObserver.cpp | 7 +++++-- libs/binder/include/binder/IUidObserver.h | 3 ++- services/sensorservice/SensorService.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'libs') diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp index 82f9047595..3d89a5f3e4 100644 --- a/libs/binder/IUidObserver.cpp +++ b/libs/binder/IUidObserver.cpp @@ -56,13 +56,15 @@ public: remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); } - virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq) + virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq, + int32_t capability) { Parcel data, reply; data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor()); data.writeInt32((int32_t) uid); data.writeInt32(procState); data.writeInt64(procStateSeq); + data.writeInt32(capability); remote()->transact(ON_UID_STATE_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); } }; @@ -104,7 +106,8 @@ status_t BnUidObserver::onTransact( uid_t uid = data.readInt32(); int32_t procState = data.readInt32(); int64_t procStateSeq = data.readInt64(); - onUidStateChanged(uid, procState, procStateSeq); + int32_t capability = data.readInt32(); + onUidStateChanged(uid, procState, procStateSeq, capability); return NO_ERROR; } break; default: diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h index a1f530dc71..9089f32141 100644 --- a/libs/binder/include/binder/IUidObserver.h +++ b/libs/binder/include/binder/IUidObserver.h @@ -34,7 +34,8 @@ public: virtual void onUidGone(uid_t uid, bool disabled) = 0; virtual void onUidActive(uid_t uid) = 0; virtual void onUidIdle(uid_t uid, bool disabled) = 0; - virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq) = 0; + virtual void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq, + int32_t capability) = 0; enum { ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 060b5eba70..fa23da0468 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -180,7 +180,7 @@ private: void onUidActive(uid_t uid); void onUidIdle(uid_t uid, bool disabled); void onUidStateChanged(uid_t uid __unused, int32_t procState __unused, - int64_t procStateSeq __unused) {} + int64_t procStateSeq __unused, int32_t capability __unused) {} void addOverrideUid(uid_t uid, bool active); void removeOverrideUid(uid_t uid); -- cgit v1.2.3-59-g8ed1b From 2b0cd8de19458f8c753d403a2b27807be1f9f027 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Mon, 26 Aug 2019 10:30:52 -0700 Subject: Make Transaction inherit Parcelable at public level Bug: 139439952 Test: build, boot, SurfaceFlinger_test Change-Id: Ib0796def398cbeb295d6cd95b8422ab66bb0b2c5 --- libs/gui/include/gui/SurfaceComposerClient.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f303a03254..64ee65f623 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -290,7 +290,7 @@ public: std::unordered_set, SCHash> surfaceControls; }; - class Transaction : Parcelable { + class Transaction : public Parcelable { std::unordered_map, ComposerState, IBinderHash> mComposerStates; SortedVector mDisplayStates; std::unordered_map, CallbackInfo, TCLHash> -- cgit v1.2.3-59-g8ed1b From 66a877723cc8019ec828a3fc8372d364f02384df Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 24 Jun 2019 16:30:00 -0700 Subject: Support noted appops collection in native code With change I96ded4a8d8d9bcb37a4555d9b1281cb57945ffa9 the system now allows apps to collect all app-ops that are noted for them. Native code can also note app-op. Unfortunately there is no guaranteed way how an app's native code can interact with java code that might or might not be running in the same process. Hence we cannot support sending the noted app-ops back to the caller over binders. Hence all notes app-ops will need to be collected as AsyncNotedOps Test: atest CtsAppOpsTestCases (includes tests that note app-ops natively) Bug: 136505050 Change-Id: I5dc479468c8dae3b10f071123b0535a288bf8662 --- libs/binder/Android.bp | 2 - libs/binder/AppOpsManager.cpp | 86 ++++++++++++++++++++++++++++- libs/binder/IAppOpsService.cpp | 62 ++++++++++++++++++++- libs/binder/include/binder/AppOpsManager.h | 35 ++++++++++-- libs/binder/include/binder/IAppOpsService.h | 15 +++-- 5 files changed, 184 insertions(+), 16 deletions(-) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 027418a035..0b71d1f60c 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -86,10 +86,8 @@ cc_library_shared { vendor: { exclude_srcs: [ "ActivityManager.cpp", - "AppOpsManager.cpp", "IActivityManager.cpp", "IAppOpsCallback.cpp", - "IAppOpsService.cpp", "IBatteryStats.cpp", "IMediaResourceMonitor.cpp", "IPermissionController.cpp", diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 525685c35e..48b218e78b 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -21,10 +21,18 @@ #include +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "AppOpsManager" + namespace android { namespace { +#ifndef __ANDROID_VNDK__ #if defined(__BRILLO__) // Because Brillo has no application model, security policy is managed // statically (at build time) with SELinux controls. @@ -33,13 +41,17 @@ const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED; #else const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED; #endif // defined(__BRILLO__) +#endif // __ANDROID_VNDK__ } // namespace static String16 _appops("appops"); +#ifndef __ANDROID_VNDK__ static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER; +#endif // __ANDROID_VNDK__ static sp gToken; +#ifndef __ANDROID_VNDK__ static const sp& getToken(const sp& service) { pthread_mutex_lock(&gTokenMutex); if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) { @@ -48,6 +60,17 @@ static const sp& getToken(const sp& service) { pthread_mutex_unlock(&gTokenMutex); return gToken; } +#endif // __ANDROID_VNDK__ + +thread_local uint64_t notedAppOpsInThisBinderTransaction[2]; +thread_local int32_t uidOfThisBinderTransaction = -1; + +// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note +#ifndef __ANDROID_VNDK__ +uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0}; +#else +uint8_t appOpsToNote[128] = {0}; +#endif // __ANDROID_VNDK__ AppOpsManager::AppOpsManager() { @@ -85,6 +108,7 @@ sp AppOpsManager::getService() } #endif // defined(__BRILLO__) +#ifndef __ANDROID_VNDK__ int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); @@ -102,18 +126,41 @@ int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t ui } int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) { + return noteOp(op, uid, callingPackage, String16("noteOp from native code")); +} + +int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage, + const String16& message) { sp service = getService(); - return service != nullptr + int32_t mode = service != nullptr ? service->noteOperation(op, uid, callingPackage) : APP_OPS_MANAGER_UNAVAILABLE_MODE; + + if (mode == AppOpsManager::MODE_ALLOWED) { + markAppOpNoted(uid, callingPackage, op, message); + } + + return mode; } int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault) { + return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, + String16("startOpNoThrow from native code")); +} + +int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault, const String16& message) { sp service = getService(); - return service != nullptr + int32_t mode = service != nullptr ? service->startOperation(getToken(service), op, uid, callingPackage, startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE; + + if (mode == AppOpsManager::MODE_ALLOWED) { + markAppOpNoted(uid, callingPackage, op, message); + } + + return mode; } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { @@ -146,5 +193,40 @@ int32_t AppOpsManager::permissionToOpCode(const String16& permission) { return -1; } +#endif // __ANDROID_VNDK__ + +bool AppOpsManager::shouldCollectNotes(int32_t opcode) { + sp service = getService(); + if (service != nullptr) { + return service->shouldCollectNotes(opcode); + } + return false; +} + +void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode, + const String16& message) { + // check it the appops needs to be collected and cache result + if (appOpsToNote[opCode] == 0) { + if (shouldCollectNotes(opCode)) { + appOpsToNote[opCode] = 2; + } else { + appOpsToNote[opCode] = 1; + } + } + + if (appOpsToNote[opCode] != 2) { + return; + } + + noteAsyncOp(String16(), uid, packageName, opCode, message); +} + +void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid, + const String16& packageName, int32_t opCode, const String16& message) { + sp service = getService(); + if (service != nullptr) { + return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message); + } +} }; // namespace android diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index c426f3a31f..8840990824 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -34,6 +34,7 @@ public: { } +#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -111,7 +112,6 @@ public: return reply.readStrongBinder(); } - virtual int32_t permissionToOpCode(const String16& permission) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -137,6 +137,45 @@ public: } return reply.readInt32(); } + +#endif + virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, + const String16& packageName, int32_t opCode, const String16& message) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + + // Convert empty callingPackage into null string + if (callingPackageName.size() != 0) { + data.writeString16(callingPackageName); + } else { + data.writeString16(nullptr, 0); + } + + data.writeInt32(uid); + + // Convert empty packageName into null string + if (packageName.size() != 0) { + data.writeString16(packageName); + } else { + data.writeString16(nullptr, 0); + } + + data.writeInt32(opCode); + data.writeString16(message); + remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply); + } + + virtual bool shouldCollectNotes(int32_t opCode) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(opCode); + remote()->transact(SHOULD_COLLECT_NOTES_TRANSACTION, data, &reply); + // fail on exception + if (reply.readExceptionCode() != 0) { + return false; + } + return reply.readBool(); + } }; IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService"); @@ -149,6 +188,7 @@ status_t BnAppOpsService::onTransact( { //printf("AppOpsService received: "); data.print(); switch(code) { +#ifndef __ANDROID_VNDK__ case CHECK_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); @@ -234,6 +274,26 @@ status_t BnAppOpsService::onTransact( reply->writeInt32(res); return NO_ERROR; } break; +#endif // __ANDROID_VNDK__ + case NOTE_ASYNC_OP_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + String16 callingPackageName = data.readString16(); + int32_t uid = data.readInt32(); + String16 packageName = data.readString16(); + int32_t opCode = data.readInt32(); + String16 message = data.readString16(); + noteAsyncOp(callingPackageName, uid, packageName, opCode, message); + reply->writeNoException(); + return NO_ERROR; + } break; + case SHOULD_COLLECT_NOTES_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + int32_t opCode = data.readInt32(); + bool shouldCollect = shouldCollectNotes(opCode); + reply->writeNoException(); + reply->writeBool(shouldCollect); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 17493b4252..7a99396eef 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -17,8 +17,6 @@ #ifndef ANDROID_APP_OPS_MANAGER_H #define ANDROID_APP_OPS_MANAGER_H -#ifndef __ANDROID_VNDK__ - #include #include @@ -35,6 +33,7 @@ public: MODE_ERRORED = IAppOpsService::MODE_ERRORED }; +#ifndef __ANDROID_VNDK__ enum { OP_NONE = -1, OP_COARSE_LOCATION = 0, @@ -109,34 +108,58 @@ public: OP_START_FOREGROUND = 76, OP_BLUETOOTH_SCAN = 77, OP_USE_BIOMETRIC = 78, + OP_ACTIVITY_RECOGNITION = 79, + OP_SMS_FINANCIAL_TRANSACTIONS = 80, + OP_READ_MEDIA_AUDIO = 81, + OP_WRITE_MEDIA_AUDIO = 82, + OP_READ_MEDIA_VIDEO = 83, + OP_WRITE_MEDIA_VIDEO = 84, + OP_READ_MEDIA_IMAGES = 85, + OP_WRITE_MEDIA_IMAGES = 86, + OP_LEGACY_STORAGE = 87, + OP_ACCESS_ACCESSIBILITY = 88, + OP_READ_DEVICE_IDENTIFIERS = 89, + _NUM_OP = 90 }; +#endif // __ANDROID_VNDK__ AppOpsManager(); +#ifndef __ANDROID_VNDK__ int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, const String16& callingPackage); + // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage); + int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage, + const String16& message); + // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&) + // instead int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, bool startIfModeDefault); + int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, + bool startIfModeDefault, const String16& message); void finishOp(int32_t op, int32_t uid, const String16& callingPackage); void startWatchingMode(int32_t op, const String16& packageName, const sp& callback); void stopWatchingMode(const sp& callback); int32_t permissionToOpCode(const String16& permission); - +#endif // __ANDROID_VNDK__ + void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, + int32_t opCode, const String16& message); private: Mutex mLock; sp mService; sp getService(); + void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode, + const String16& message); + bool shouldCollectNotes(int32_t opCode); }; }; // namespace android + // --------------------------------------------------------------------------- -#else // __ANDROID_VNDK__ -#error "This header is not visible to vendors" -#endif // __ANDROID_VNDK__ #endif // ANDROID_APP_OPS_MANAGER_H diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 3dbd0d9f7a..9d02370015 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -19,8 +19,8 @@ #define ANDROID_IAPP_OPS_SERVICE_H #ifndef __ANDROID_VNDK__ - #include +#endif #include namespace android { @@ -32,6 +32,7 @@ class IAppOpsService : public IInterface public: DECLARE_META_INTERFACE(AppOpsService) +#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, @@ -45,8 +46,13 @@ public: virtual int32_t permissionToOpCode(const String16& permission) = 0; virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid, const String16& packageName) = 0; +#endif // __ANDROID_VNDK__ + virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, + const String16& packageName, int32_t opCode, const String16& message) = 0; + virtual bool shouldCollectNotes(int32_t opCode) = 0; enum { +#ifndef __ANDROID_VNDK__ CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1, START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2, @@ -56,6 +62,9 @@ public: GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7, CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8, +#endif // __ANDROID_VNDK__ + NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9, + SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10, }; enum { @@ -81,8 +90,4 @@ public: }; // namespace android -#else // __ANDROID_VNDK__ -#error "This header is not visible to vendors" -#endif // __ANDROID_VNDK__ - #endif // ANDROID_IAPP_OPS_SERVICE_H -- cgit v1.2.3-59-g8ed1b From f629f10f62ab695aa0a154aca9a6a53aae476163 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 6 Aug 2019 18:16:23 -0700 Subject: [ANativeWindow] Test with a TestableSurface TestableSurface is the same as a Surface but with hooks into protected members so that tests can verify that any internal state returned by the ANativeWindow interface is in fact correct. Bug: 137012161 Test: atest Change-Id: I4320cdee35ec9b523d6b321d22a13f7e61f1a77c --- libs/nativewindow/tests/ANativeWindowTest.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index a80da24a47..5247e04c32 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -29,6 +29,15 @@ using namespace android; +class TestableSurface final : public Surface { +public: + explicit TestableSurface(const sp& bufferProducer) + : Surface(bufferProducer) {} + + // Exposes the internal last dequeue duration that's stored on the Surface. + nsecs_t getLastDequeueDuration() const { return mLastDequeueDuration; } +}; + class ANativeWindowTest : public ::testing::Test { protected: void SetUp() override { @@ -37,7 +46,7 @@ protected: ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); BufferQueue::createBufferQueue(&mProducer, &mConsumer); mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN); - mWindow = new Surface(mProducer); + mWindow = new TestableSurface(mProducer); const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU); EXPECT_EQ(0, success); } @@ -52,12 +61,14 @@ protected: sp mProducer; sp mConsumer; sp mItemConsumer; - sp mWindow; + + sp mWindow; }; TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) { int result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_EQ(0, result); + EXPECT_EQ(0, mWindow->getLastDequeueDuration() / 1000); } TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { @@ -69,4 +80,5 @@ TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_GT(result, 0); + EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000); } -- cgit v1.2.3-59-g8ed1b From 8e95ee87a96bcacab17a4b49a8150fb42565ac8c Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 13 Aug 2019 12:24:25 -0700 Subject: Camera: add camera audio restriction binder call Also add the API to AppOpsManager Test: new CTS tests Bug: 135676184 Change-Id: I8bcdd34a4b6bb0fba5151677db38f8c35b7ae97e --- libs/binder/AppOpsManager.cpp | 7 +++++++ libs/binder/IAppOpsService.cpp | 14 ++++++++++++++ libs/binder/include/binder/AppOpsManager.h | 2 ++ libs/binder/include/binder/IAppOpsService.h | 5 +++++ 4 files changed, 28 insertions(+) (limited to 'libs') diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index 48b218e78b..e2af01c161 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -193,6 +193,13 @@ int32_t AppOpsManager::permissionToOpCode(const String16& permission) { return -1; } +void AppOpsManager::setCameraAudioRestriction(int32_t mode) { + sp service = getService(); + if (service != nullptr) { + service->setCameraAudioRestriction(mode); + } +} + #endif // __ANDROID_VNDK__ bool AppOpsManager::shouldCollectNotes(int32_t opcode) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index 8840990824..b6360cbffd 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -138,6 +138,13 @@ public: return reply.readInt32(); } + virtual void setCameraAudioRestriction(int32_t mode) { + Parcel data, reply; + data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); + data.writeInt32(mode); + remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply); + } + #endif virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) { @@ -274,6 +281,13 @@ status_t BnAppOpsService::onTransact( reply->writeInt32(res); return NO_ERROR; } break; + case SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION: { + CHECK_INTERFACE(IAppOpsService, data, reply); + const int32_t mode = data.readInt32(); + setCameraAudioRestriction(mode); + reply->writeNoException(); + return NO_ERROR; + } break; #endif // __ANDROID_VNDK__ case NOTE_ASYNC_OP_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 7a99396eef..dff4d49596 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -144,9 +144,11 @@ public: const sp& callback); void stopWatchingMode(const sp& callback); int32_t permissionToOpCode(const String16& permission); + void setCameraAudioRestriction(int32_t mode); #endif // __ANDROID_VNDK__ void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message); + private: Mutex mLock; sp mService; diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 9d02370015..009ef6c7a7 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -46,6 +46,7 @@ public: virtual int32_t permissionToOpCode(const String16& permission) = 0; virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid, const String16& packageName) = 0; + virtual void setCameraAudioRestriction(int32_t mode) = 0; #endif // __ANDROID_VNDK__ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) = 0; @@ -65,6 +66,10 @@ public: #endif // __ANDROID_VNDK__ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9, SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10, +#ifndef __ANDROID_VNDK__ + SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11, +#endif // __ANDROID_VNDK__ + }; enum { -- cgit v1.2.3-59-g8ed1b From a4f14de792bf6bc8bab907db172fd26c034aa515 Mon Sep 17 00:00:00 2001 From: mamik Date: Fri, 30 Aug 2019 07:27:14 -0700 Subject: Update external display property in hardware_composer. This change removes the "persist.vr.use_external_display" property and updates the code path to always allow external displays. Bug: 140287770 Test: Manual, ran on device and verified that it works Change-Id: I8bedeb18c93b2a9dc3815177aa9a6a897b63c81e --- libs/vr/libvrflinger/hardware_composer.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'libs') diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index e1240d6311..9072d89d76 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -51,8 +51,6 @@ const char kDvrStandaloneProperty[] = "ro.boot.vr"; const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns"; -const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display"; - // Surface flinger uses "VSYNC-sf" and "VSYNC-app" for its version of these // events. Name ours similarly. const char kVsyncTraceEventName[] = "VSYNC-vrflinger"; @@ -965,18 +963,9 @@ bool HardwareComposer::UpdateTargetDisplay() { external_display_ = GetDisplayParams(composer_.get(), *displays.external_display, /*is_primary*/ false); - if (property_get_bool(kUseExternalDisplayProperty, false)) { - ALOGI("External display connected. Switching to external display."); - target_display_ = &(*external_display_); - target_display_changed = true; - } else { - ALOGI("External display connected, but sysprop %s is unset, so" - " using primary display.", kUseExternalDisplayProperty); - if (was_using_external_display) { - target_display_ = &primary_display_; - target_display_changed = true; - } - } + ALOGI("External display connected. Switching to external display."); + target_display_ = &(*external_display_); + target_display_changed = true; } else { // External display was disconnected external_display_ = std::nullopt; -- cgit v1.2.3-59-g8ed1b From 94e91f62bb251bc08864e1aa5f0e9e30908ba35d Mon Sep 17 00:00:00 2001 From: mamik Date: Mon, 19 Aug 2019 09:11:33 -0700 Subject: Rev up vr_hwc to composer@2.3 Fix for issue: "[GSI XR] VrFlinger doesn't work on GSI/MTP845." The flow that causes the issue is: SurfaceFlinger gets an hotplug event and adds a display id of the internal display (For instance, display id of 19260371107735809). This display id gets added to the HWComposer through the hotplug event. When updateVrFlinger() is eventually called in SurfaceFlinger, a new HWComposer is created which has no display ids being tracked in HWComposer. Another hotplug event starts from vr_hwc.cpp, which has a display id of 0. SurfaceFlinger receives this hot plug event so SurfaceFlinger has an display ids of [19260371107735809, 0]. HWComposer only has display id 0. Next processDisplayChangesLocked() is called in SurfaceFlinger and a new FramebufferSurface is created with display id 19260371107735809. In the FramebufferSurface it tries to call getActiveConfig() in HWComposer with the display id of 19260371107735809, which HWComposer does not know about. This results in a crash. The display id is created from the edid data and display port. The fix is to have the vr_hwc return the same edid data and display port as the internal display. This will make the display id originating from vr_hwc be the same as the internal display id. SurfaceFlinger will now only have the display id of 19260371107735809, since it does not overwrite the same display id on the hotplug events. HWComposer will only have display id of 19260371107735809. The SurfaceFlinger and HwComposer display ids match the code works correctly now. This is accomplished by creating a version 2.0 of the vr_composer_client and having vr_hwc inherit from version 2.3 instead of version 2.1 of the composer hal. These changes are required to be able to pass through the edid data. The display port and edid data is retrieved by vr_hwc via the display_client. The other required changes needed for this to work is: ag/9215156 ag/9226524 Bug: 137325030 Bug: 138938154 Bug: 137448042 Test: manual - ran through modified unit test to make sure the edid data was returned on the MTP 845. Change-Id: I1c54e6cfda348260cf1013d6dca0dda58acb3b3c --- libs/vr/libdisplay/display_client.cpp | 4 + .../include/private/dvr/display_client.h | 1 + .../include/private/dvr/display_protocol.h | 3 + libs/vr/libvrflinger/Android.bp | 2 +- libs/vr/libvrflinger/display_service.cpp | 13 +- libs/vr/libvrflinger/display_service.h | 2 + services/surfaceflinger/Android.bp | 21 +- .../surfaceflinger/CompositionEngine/Android.bp | 2 +- .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 44 ++- .../surfaceflinger/DisplayHardware/ComposerHal.h | 16 +- services/vr/hardware_composer/Android.bp | 16 +- .../hardware_composer/impl/vr_composer_client.cpp | 22 +- .../vr/hardware_composer/impl/vr_composer_client.h | 15 +- services/vr/hardware_composer/impl/vr_hwc.cpp | 296 +++++++++++++++------ services/vr/hardware_composer/impl/vr_hwc.h | 173 ++++++++---- 15 files changed, 456 insertions(+), 174 deletions(-) (limited to 'libs') diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp index f67e258cee..62856dfbf8 100644 --- a/libs/vr/libdisplay/display_client.cpp +++ b/libs/vr/libdisplay/display_client.cpp @@ -178,6 +178,10 @@ Status DisplayClient::GetConfigurationData( return status; } +Status DisplayClient::GetDisplayIdentificationPort() { + return InvokeRemoteMethod(); +} + Status> DisplayClient::CreateSurface( const SurfaceAttributes& attributes) { int error; diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h index f8f5b3ddb3..81546ac5c2 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_client.h +++ b/libs/vr/libdisplay/include/private/dvr/display_client.h @@ -72,6 +72,7 @@ class DisplayClient : public pdx::ClientBase { public: pdx::Status GetDisplayMetrics(); pdx::Status GetConfigurationData(ConfigFileType config_type); + pdx::Status GetDisplayIdentificationPort(); pdx::Status> SetupGlobalBuffer( DvrGlobalBufferKey key, size_t size, uint64_t usage); pdx::Status DeleteGlobalBuffer(DvrGlobalBufferKey key); diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h index 861dc6c2a0..9f4cc4afcc 100644 --- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h +++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h @@ -211,6 +211,7 @@ struct DisplayProtocol { kOpGetSurfaceInfo, kOpCreateQueue, kOpSetAttributes, + kOpGetDisplayIdentificationPort, }; // Aliases. @@ -221,6 +222,8 @@ struct DisplayProtocol { PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void)); PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData, std::string(ConfigFileType config_type)); + PDX_REMOTE_METHOD(GetDisplayIdentificationPort, + kOpGetDisplayIdentificationPort, uint8_t(Void)); PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer, LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size, uint64_t usage)); diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp index 282935307c..444167227c 100644 --- a/libs/vr/libvrflinger/Android.bp +++ b/libs/vr/libvrflinger/Android.bp @@ -35,7 +35,7 @@ staticLibraries = [ ] sharedLibraries = [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 8980a92776..5a9360c2ae 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -47,7 +47,8 @@ DisplayService::DisplayService(Hwc2::Composer* hidl, uint8_t port; const auto error = hidl->getDisplayIdentificationData( - primary_display_id, &port, &display_identification_data_); + primary_display_id, &display_identification_port_, + &display_identification_data_); if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { if (error != android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { @@ -151,6 +152,11 @@ Status DisplayService::HandleMessage(pdx::Message& message) { *this, &DisplayService::OnGetConfigurationData, message); return {}; + case DisplayProtocol::GetDisplayIdentificationPort::Opcode: + DispatchRemoteMethod( + *this, &DisplayService::OnGetDisplayIdentificationPort, message); + return {}; + case DisplayProtocol::CreateSurface::Opcode: DispatchRemoteMethod( *this, &DisplayService::OnCreateSurface, message); @@ -238,6 +244,11 @@ pdx::Status DisplayService::OnGetConfigurationData( return std::move(data); } +pdx::Status DisplayService::OnGetDisplayIdentificationPort( + pdx::Message& /*message*/) { + return display_identification_port_; +} + // Creates a new DisplaySurface and associates it with this channel. This may // only be done once per channel. Status DisplayService::OnCreateSurface( diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index d45a61fad7..06ba566d32 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -82,6 +82,7 @@ class DisplayService : public pdx::ServiceBase { pdx::Status OnGetMetrics(pdx::Message& message); pdx::Status OnGetConfigurationData( pdx::Message& message, display::ConfigFileType config_type); + pdx::Status OnGetDisplayIdentificationPort(pdx::Message& message); pdx::Status OnCreateSurface( pdx::Message& message, const display::SurfaceAttributes& attributes); pdx::Status OnSetupGlobalBuffer( @@ -121,6 +122,7 @@ class DisplayService : public pdx::ServiceBase { void operator=(const DisplayService&) = delete; DisplayIdentificationData display_identification_data_; + uint8_t display_identification_port_; }; } // namespace dvr diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index afb9cec4cc..97b7697485 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -19,7 +19,7 @@ cc_defaults { "-DEGL_EGLEXT_PROTOTYPES", ], shared_libs: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.configstore-utils", "android.hardware.configstore@1.0", "android.hardware.configstore@1.1", @@ -58,6 +58,14 @@ cc_defaults { "libutils", "libSurfaceFlingerProp", ], + // VrComposer is not used when building surfaceflinger for vendors + target: { + vendor: { + exclude_shared_libs: [ + "android.frameworks.vr.composer@2.0", + ], + }, + }, static_libs: [ "libcompositionengine", "librenderengine", @@ -177,6 +185,17 @@ cc_library_shared { // can be easily replaced. "SurfaceFlingerFactory.cpp", ], + cflags: [ + "-DUSE_VR_COMPOSER=1", + ], + // VrComposer is not used when building surfaceflinger for vendors + target: { + vendor: { + cflags: [ + "-DUSE_VR_COMPOSER=0", + ], + }, + }, logtags: ["EventLog/EventLogTags.logtags"], } diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index ae6bdbce60..d2e95d05a1 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -5,7 +5,7 @@ cc_defaults { "-DLOG_TAG=\"CompositionEngine\"", ], shared_libs: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.composer@2.1", "android.hardware.graphics.composer@2.2", diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 7f47a2ecd4..e53d09949c 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -110,6 +110,7 @@ Error unwrapRet(Return& ret) namespace impl { +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {} @@ -160,6 +161,7 @@ void Composer::CommandWriter::writeBufferMetadata( writeSigned(static_cast(metadata.format)); write64(metadata.usage); } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Composer::Composer(const std::string& serviceName) : mWriter(kWriterInitialSize), @@ -198,12 +200,14 @@ Composer::Composer(const std::string& serviceName) LOG_ALWAYS_FATAL("failed to create composer client"); } +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER if (mIsUsingVrComposer) { sp vrClient = IVrComposerClient::castFrom(mClient); if (vrClient == nullptr) { LOG_ALWAYS_FATAL("failed to create vr composer client"); } } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER } Composer::~Composer() = default; @@ -565,17 +569,20 @@ Error Composer::setClientTarget(Display display, uint32_t slot, const std::vector& damage) { mWriter.selectDisplay(display); + +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER if (mIsUsingVrComposer && target.get()) { IVrComposerClient::BufferMetadata metadata = { - .width = target->getWidth(), - .height = target->getHeight(), - .stride = target->getStride(), - .layerCount = target->getLayerCount(), - .format = static_cast(target->getPixelFormat()), - .usage = target->getUsage(), + .width = target->getWidth(), + .height = target->getHeight(), + .stride = target->getStride(), + .layerCount = target->getLayerCount(), + .format = static_cast(target->getPixelFormat()), + .usage = target->getUsage(), }; mWriter.setClientTargetMetadata(metadata); } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER const native_handle_t* handle = nullptr; if (target.get()) { @@ -695,17 +702,20 @@ Error Composer::setLayerBuffer(Display display, Layer layer, { mWriter.selectDisplay(display); mWriter.selectLayer(layer); + +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER if (mIsUsingVrComposer && buffer.get()) { IVrComposerClient::BufferMetadata metadata = { - .width = buffer->getWidth(), - .height = buffer->getHeight(), - .stride = buffer->getStride(), - .layerCount = buffer->getLayerCount(), - .format = static_cast(buffer->getPixelFormat()), - .usage = buffer->getUsage(), + .width = buffer->getWidth(), + .height = buffer->getHeight(), + .stride = buffer->getStride(), + .layerCount = buffer->getLayerCount(), + .format = static_cast(buffer->getPixelFormat()), + .usage = buffer->getUsage(), }; mWriter.setLayerBufferMetadata(metadata); } +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER const native_handle_t* handle = nullptr; if (buffer.get()) { @@ -823,6 +833,7 @@ Error Composer::setLayerZOrder(Display display, Layer layer, uint32_t z) return Error::NONE; } +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type, uint32_t appId) { @@ -833,6 +844,15 @@ Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type, } return Error::NONE; } +#else +Error Composer::setLayerInfo(Display display, Layer layer, uint32_t, uint32_t) { + if (mIsUsingVrComposer) { + mWriter.selectDisplay(display); + mWriter.selectLayer(layer); + } + return Error::NONE; +} +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER Error Composer::execute() { diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index c4e952b8d9..9f6cac22b7 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -23,7 +23,9 @@ #include #include -#include +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER +#include +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER #include #include #include @@ -38,7 +40,9 @@ namespace android { namespace Hwc2 { -using frameworks::vr::composer::V1_0::IVrComposerClient; +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER +using frameworks::vr::composer::V2_0::IVrComposerClient; +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER namespace types = hardware::graphics::common; @@ -418,6 +422,7 @@ public: Error setDisplayBrightness(Display display, float brightness) override; private: +#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER class CommandWriter : public CommandWriterBase { public: explicit CommandWriter(uint32_t initialMaxSize); @@ -433,6 +438,13 @@ private: void writeBufferMetadata( const IVrComposerClient::BufferMetadata& metadata); }; +#else + class CommandWriter : public CommandWriterBase { + public: + explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {} + ~CommandWriter() override {} + }; +#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER // Many public functions above simply write a command into the command // queue to batch the calls. validateDisplay and presentDisplay will call diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index bc7cc1c409..2cfeda3760 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -12,8 +12,10 @@ cc_library_shared { ], shared_libs: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.1-resources", "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@3.0", @@ -34,11 +36,11 @@ cc_library_shared { header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", - "android.hardware.graphics.composer@2.1-hal", + "android.hardware.graphics.composer@2.3-hal", ], export_header_lib_headers: [ - "android.hardware.graphics.composer@2.1-hal", + "android.hardware.graphics.composer@2.3-hal", ], export_static_lib_headers: [ @@ -46,8 +48,10 @@ cc_library_shared { ], export_shared_lib_headers: [ - "android.frameworks.vr.composer@1.0", + "android.frameworks.vr.composer@2.0", "android.hardware.graphics.composer@2.1", + "android.hardware.graphics.composer@2.2", + "android.hardware.graphics.composer@2.3", ], export_include_dirs: ["."], @@ -104,8 +108,8 @@ cc_binary { "libvr_hwc-binder", ], shared_libs: [ - "android.frameworks.vr.composer@1.0", - "android.hardware.graphics.composer@2.1", + "android.frameworks.vr.composer@2.0", + "android.hardware.graphics.composer@2.3", "libbase", "libbinder", "liblog", diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp index 786d5fac98..36f6b32e3f 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.cpp +++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -27,8 +27,7 @@ namespace android { namespace dvr { -using android::hardware::graphics::common::V1_0::PixelFormat; -using android::frameworks::vr::composer::V1_0::IVrComposerClient; +using android::frameworks::vr::composer::V2_0::IVrComposerClient; VrComposerClient::VrComposerClient(dvr::VrHwc& hal) : ComposerClient(&hal), mVrHal(hal) { @@ -51,7 +50,8 @@ VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client) VrComposerClient::VrCommandEngine::~VrCommandEngine() {} bool VrComposerClient::VrCommandEngine::executeCommand( - IComposerClient::Command command, uint16_t length) { + hardware::graphics::composer::V2_1::IComposerClient::Command command, + uint16_t length) { IVrComposerClient::VrCommand vrCommand = static_cast(command); switch (vrCommand) { @@ -107,12 +107,14 @@ bool VrComposerClient::VrCommandEngine::executeSetLayerBufferMetadata( IVrComposerClient::BufferMetadata VrComposerClient::VrCommandEngine::readBufferMetadata() { IVrComposerClient::BufferMetadata metadata = { - .width = read(), - .height = read(), - .stride = read(), - .layerCount = read(), - .format = static_cast(readSigned()), - .usage = read64(), + .width = read(), + .height = read(), + .stride = read(), + .layerCount = read(), + .format = + static_cast( + readSigned()), + .usage = read64(), }; return metadata; } diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h index 0b7ce5e665..1b2b5f4f56 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.h +++ b/services/vr/hardware_composer/impl/vr_composer_client.h @@ -17,10 +17,12 @@ #ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H #define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H -#include -#include +#include +#include #include #include +#include +#include namespace android { namespace dvr { @@ -28,8 +30,8 @@ namespace dvr { class VrHwc; using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine; -using hardware::graphics::composer::V2_1::hal::ComposerHal; -using hardware::graphics::composer::V2_1::hal::detail::ComposerClientImpl; +using hardware::graphics::composer::V2_3::hal::ComposerHal; +using hardware::graphics::composer::V2_3::hal::detail::ComposerClientImpl; using ComposerClient = ComposerClientImpl; @@ -44,8 +46,9 @@ class VrComposerClient : public ComposerClient { explicit VrCommandEngine(VrComposerClient& client); ~VrCommandEngine() override; - bool executeCommand(IComposerClient::Command command, - uint16_t length) override; + bool executeCommand( + hardware::graphics::composer::V2_1::IComposerClient::Command command, + uint16_t length) override; private: bool executeSetLayerInfo(uint16_t length); diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp index 7323277248..e530b16b1b 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ b/services/vr/hardware_composer/impl/vr_hwc.cpp @@ -27,7 +27,7 @@ #include "vr_composer_client.h" using namespace android::hardware::graphics::common::V1_0; -using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_3; using android::base::StringPrintf; using android::hardware::hidl_handle; @@ -36,12 +36,12 @@ using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; +namespace types = android::hardware::graphics::common; + namespace android { namespace dvr { namespace { -using android::hardware::graphics::common::V1_0::PixelFormat; - const Display kDefaultDisplayId = 1; const Config kDefaultConfigId = 1; @@ -269,7 +269,8 @@ void VrHwc::registerEventCallback(EventCallback* callback) { // onHotplug() call, so it's important to release mutex_ here. lock.unlock(); event_callback_->onHotplug(kDefaultDisplayId, - IComposerCallback::Connection::CONNECTED); + hardware::graphics::composer::V2_1:: + IComposerCallback::Connection::CONNECTED); lock.lock(); UpdateVsyncCallbackEnabledLocked(); } @@ -282,15 +283,6 @@ void VrHwc::unregisterEventCallback() { uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; } -Error VrHwc::createVirtualDisplay(uint32_t width, uint32_t height, - PixelFormat* format, Display* outDisplay) { - *format = PixelFormat::RGBA_8888; - *outDisplay = display_count_; - displays_[display_count_].reset(new HwcDisplay(width, height)); - display_count_++; - return Error::NONE; -} - Error VrHwc::destroyVirtualDisplay(Display display) { std::lock_guard guard(mutex_); if (display == kDefaultDisplayId || displays_.erase(display) == 0) @@ -332,24 +324,6 @@ Error VrHwc::getActiveConfig(Display display, Config* outConfig) { return Error::NONE; } -Error VrHwc::getClientTargetSupport(Display display, uint32_t /* width */, - uint32_t /* height */, - PixelFormat /* format */, - Dataspace /* dataspace */) { - std::lock_guard guard(mutex_); - if (!FindDisplay(display)) - return Error::BAD_DISPLAY; - - return Error::NONE; -} - -Error VrHwc::getColorModes(Display /* display */, - hidl_vec* outModes) { - std::vector color_modes(1, ColorMode::NATIVE); - *outModes = hidl_vec(color_modes); - return Error::NONE; -} - Error VrHwc::getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) { @@ -441,17 +415,6 @@ Error VrHwc::getDozeSupport(Display display, bool* outSupport) { return Error::NONE; } -Error VrHwc::getHdrCapabilities(Display /* display */, - hidl_vec* /* outTypes */, - float* outMaxLuminance, - float* outMaxAverageLuminance, - float* outMinLuminance) { - *outMaxLuminance = 0; - *outMaxAverageLuminance = 0; - *outMinLuminance = 0; - return Error::NONE; -} - Error VrHwc::setActiveConfig(Display display, Config config) { std::lock_guard guard(mutex_); auto display_ptr = FindDisplay(display); @@ -464,47 +427,6 @@ Error VrHwc::setActiveConfig(Display display, Config config) { return Error::NONE; } -Error VrHwc::setColorMode(Display display, ColorMode mode) { - std::lock_guard guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) - return Error::BAD_PARAMETER; - - display_ptr->set_color_mode(mode); - return Error::NONE; -} - -Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) { - bool dozeSupported = false; - - Error dozeSupportError = getDozeSupport(display, &dozeSupported); - - if (dozeSupportError != Error::NONE) - return dozeSupportError; - - std::lock_guard guard(mutex_); - auto display_ptr = FindDisplay(display); - if (!display_ptr) - return Error::BAD_DISPLAY; - - if (mode < IComposerClient::PowerMode::OFF || - mode > IComposerClient::PowerMode::DOZE_SUSPEND) { - return Error::BAD_PARAMETER; - } - - if (!dozeSupported && - (mode == IComposerClient::PowerMode::DOZE || - mode == IComposerClient::PowerMode::DOZE_SUSPEND)) { - return Error::UNSUPPORTED; - } - - display_ptr->set_power_mode(mode); - return Error::NONE; -} - Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) { std::lock_guard guard(mutex_); auto display_ptr = FindDisplay(display); @@ -956,6 +878,23 @@ Return VrHwc::createClient(createClient_cb hidl_cb) { return Void(); } +Return VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) { + std::lock_guard guard(mutex_); + + Error status = Error::NONE; + sp client; + if (!client_.promote().get()) { + client = new VrComposerClient(*this); + } else { + ALOGE("Already have a client"); + status = Error::NO_RESOURCES; + } + + client_ = client; + hidl_cb(status, client); + return Void(); +} + void VrHwc::ForceDisplaysRefresh() { std::lock_guard guard(mutex_); if (event_callback_ != nullptr) { @@ -1044,5 +983,196 @@ void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) { callback_ = callback; } +// composer::V2_2::ComposerHal +Error VrHwc::setReadbackBuffer(Display display, + const native_handle_t* bufferHandle, + android::base::unique_fd fenceFd) { + return Error::NONE; +} + +Error VrHwc::getReadbackBufferFence(Display display, + android::base::unique_fd* outFenceFd) { + return Error::NONE; +} + +Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height, + types::V1_1::PixelFormat* format, + Display* outDisplay) { + *format = types::V1_1::PixelFormat::RGBA_8888; + *outDisplay = display_count_; + displays_[display_count_].reset(new HwcDisplay(width, height)); + display_count_++; + return Error::NONE; +} + +Error VrHwc::setPowerMode_2_2(Display display, + IComposerClient::PowerMode mode) { + bool dozeSupported = false; + + Error dozeSupportError = getDozeSupport(display, &dozeSupported); + + if (dozeSupportError != Error::NONE) + return dozeSupportError; + + std::lock_guard guard(mutex_); + auto display_ptr = FindDisplay(display); + if (!display_ptr) + return Error::BAD_DISPLAY; + + if (mode < IComposerClient::PowerMode::OFF || + mode > IComposerClient::PowerMode::DOZE_SUSPEND) { + return Error::BAD_PARAMETER; + } + + if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE || + mode == IComposerClient::PowerMode::DOZE_SUSPEND)) { + return Error::UNSUPPORTED; + } + + display_ptr->set_power_mode(mode); + return Error::NONE; +} + +Error VrHwc::setLayerFloatColor(Display display, Layer layer, + IComposerClient::FloatColor color) { + return Error::NONE; +} + +Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode, + std::vector* outIntents) { + return Error::NONE; +} + +std::array VrHwc::getDataspaceSaturationMatrix( + types::V1_1::Dataspace dataspace) { + return {}; +} + +// composer::V2_3::ComposerHal +Error VrHwc::getHdrCapabilities_2_3(Display /*display*/, + hidl_vec* /*outTypes*/, + float* outMaxLuminance, + float* outMaxAverageLuminance, + float* outMinLuminance) { + *outMaxLuminance = 0; + *outMaxAverageLuminance = 0; + *outMinLuminance = 0; + return Error::NONE; +} + +Error VrHwc::setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector& metadata) { + return Error::NONE; +} + +Error VrHwc::getPerFrameMetadataKeys_2_3( + Display display, + std::vector* outKeys) { + return Error::NONE; +} + +Error VrHwc::setColorMode_2_3(Display display, ColorMode mode, + RenderIntent intent) { + std::lock_guard guard(mutex_); + auto display_ptr = FindDisplay(display); + if (!display_ptr) + return Error::BAD_DISPLAY; + + if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3) + return Error::BAD_PARAMETER; + + display_ptr->set_color_mode(mode); + return Error::NONE; +} + +Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode, + std::vector* outIntents) { + return Error::NONE; +} + +Error VrHwc::getColorModes_2_3(Display display, hidl_vec* outModes) { + return Error::NONE; +} + +Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width, + uint32_t height, PixelFormat format, + Dataspace dataspace) { + return Error::NONE; +} + +Error VrHwc::getReadbackBufferAttributes_2_3(Display display, + PixelFormat* outFormat, + Dataspace* outDataspace) { + return Error::NONE; +} + +Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* outData) { + int error = 0; + auto display_client = display::DisplayClient::Create(&error); + if (!display_client) { + ALOGE("Could not connect to display service : %s(%d)", strerror(error), + error); + return Error::BAD_CONFIG; + } + auto edid_data = display_client->GetConfigurationData( + display::ConfigFileType::kDeviceEdid); + auto display_identification_port = + display_client->GetDisplayIdentificationPort(); + *outPort = display_identification_port.get(); + + std::copy(edid_data.get().begin(), edid_data.get().end(), + std::back_inserter(*outData)); + return Error::NONE; +} + +Error VrHwc::setLayerColorTransform(Display display, Layer layer, + const float* matrix) { + return Error::NONE; +} + +Error VrHwc::getDisplayedContentSamplingAttributes( + Display display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield& componentMask) { + return Error::NONE; +} + +Error VrHwc::setDisplayedContentSamplingEnabled( + Display display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, + uint64_t maxFrames) { + return Error::NONE; +} + +Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames, + uint64_t timestamp, uint64_t& frameCount, + hidl_vec& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& sampleComponent3) { + return Error::NONE; +} + +Error VrHwc::getDisplayCapabilities( + Display display, + std::vector* outCapabilities) { + return Error::NONE; +} + +Error VrHwc::setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector& blobs) { + return Error::NONE; +} + +Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) { + return Error::NONE; +} + +Error VrHwc::setDisplayBrightness(Display display, float brightness) { + return Error::NONE; +} + } // namespace dvr } // namespace android diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h index 15358c57bb..3e3a6307fa 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ b/services/vr/hardware_composer/impl/vr_hwc.h @@ -17,9 +17,9 @@ #define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -28,15 +28,21 @@ #include #include -using namespace android::frameworks::vr::composer::V1_0; +using namespace android::frameworks::vr::composer::V2_0; using namespace android::hardware::graphics::common::V1_0; -using namespace android::hardware::graphics::composer::V2_1; +using namespace android::hardware::graphics::composer::V2_3; +using android::hardware::hidl_bitfield; using android::hardware::hidl_handle; using android::hardware::hidl_string; using android::hardware::hidl_vec; using android::hardware::Return; using android::hardware::Void; +using android::hardware::graphics::composer::V2_1::Config; +using android::hardware::graphics::composer::V2_1::Display; +using android::hardware::graphics::composer::V2_1::Error; +using android::hardware::graphics::composer::V2_1::Layer; +using android::hardware::graphics::composer::V2_3::IComposerClient; namespace android { @@ -46,16 +52,23 @@ namespace dvr { class VrComposerClient; -using android::hardware::graphics::common::V1_0::PixelFormat; -using android::hardware::graphics::composer::V2_1::hal::ComposerHal; +using android::hardware::graphics::composer::V2_3::hal::ComposerHal; + +namespace types = android::hardware::graphics::common; + +using types::V1_1::RenderIntent; +using types::V1_2::ColorMode; +using types::V1_2::Dataspace; +using types::V1_2::Hdr; +using types::V1_2::PixelFormat; class ComposerView { public: struct ComposerLayer { - using Recti = hardware::graphics::composer::V2_1::IComposerClient::Rect; - using Rectf = hardware::graphics::composer::V2_1::IComposerClient::FRect; + using Recti = hardware::graphics::composer::V2_3::IComposerClient::Rect; + using Rectf = hardware::graphics::composer::V2_3::IComposerClient::FRect; using BlendMode = - hardware::graphics::composer::V2_1::IComposerClient::BlendMode; + hardware::graphics::composer::V2_3::IComposerClient::BlendMode; Layer id; sp buffer; @@ -111,7 +124,7 @@ class ComposerView { struct HwcLayer { using Composition = - hardware::graphics::composer::V2_1::IComposerClient::Composition; + hardware::graphics::composer::V2_3::IComposerClient::Composition; explicit HwcLayer(Layer new_id) { info.id = new_id; } @@ -205,90 +218,148 @@ class VrHwc : public IComposer, public ComposerHal, public ComposerView { Display display, Layer layer, const IVrComposerClient::BufferMetadata& metadata); - // ComposerHal + // composer::V2_1::ComposerHal bool hasCapability(hwc2_capability_t capability) override; std::string dumpDebugInfo() override { return {}; } - void registerEventCallback(EventCallback* callback) override; + + void registerEventCallback(ComposerHal::EventCallback* callback) override; void unregisterEventCallback() override; uint32_t getMaxVirtualDisplayCount() override; - Error createVirtualDisplay(uint32_t width, uint32_t height, - PixelFormat* format, Display* outDisplay) override; Error destroyVirtualDisplay(Display display) override; Error createLayer(Display display, Layer* outLayer) override; Error destroyLayer(Display display, Layer layer) override; Error getActiveConfig(Display display, Config* outConfig) override; - Error getClientTargetSupport(Display display, - uint32_t width, uint32_t height, - PixelFormat format, Dataspace dataspace) override; - Error getColorModes(Display display, hidl_vec* outModes) override; Error getDisplayAttribute(Display display, Config config, - IComposerClient::Attribute attribute, int32_t* outValue) override; + IComposerClient::Attribute attribute, + int32_t* outValue) override; Error getDisplayConfigs(Display display, hidl_vec* outConfigs) override; Error getDisplayName(Display display, hidl_string* outName) override; Error getDisplayType(Display display, - IComposerClient::DisplayType* outType) override; + IComposerClient::DisplayType* outType) override; Error getDozeSupport(Display display, bool* outSupport) override; - Error getHdrCapabilities(Display display, hidl_vec* outTypes, - float* outMaxLuminance, float* outMaxAverageLuminance, - float* outMinLuminance) override; Error setActiveConfig(Display display, Config config) override; - Error setColorMode(Display display, ColorMode mode) override; - Error setPowerMode(Display display, IComposerClient::PowerMode mode) override; Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override; Error setColorTransform(Display display, const float* matrix, - int32_t hint) override; + int32_t hint) override; Error setClientTarget(Display display, buffer_handle_t target, - int32_t acquireFence, int32_t dataspace, - const std::vector& damage) override; + int32_t acquireFence, int32_t dataspace, + const std::vector& damage) override; Error setOutputBuffer(Display display, buffer_handle_t buffer, - int32_t releaseFence) override; - Error validateDisplay(Display display, - std::vector* outChangedLayers, - std::vector* outCompositionTypes, - uint32_t* outDisplayRequestMask, - std::vector* outRequestedLayers, - std::vector* outRequestMasks) override; + int32_t releaseFence) override; + Error validateDisplay( + Display display, std::vector* outChangedLayers, + std::vector* outCompositionTypes, + uint32_t* outDisplayRequestMask, std::vector* outRequestedLayers, + std::vector* outRequestMasks) override; Error acceptDisplayChanges(Display display) override; Error presentDisplay(Display display, int32_t* outPresentFence, - std::vector* outLayers, - std::vector* outReleaseFences) override; + std::vector* outLayers, + std::vector* outReleaseFences) override; - Error setLayerCursorPosition(Display display, Layer layer, - int32_t x, int32_t y) override; - Error setLayerBuffer(Display display, Layer layer, - buffer_handle_t buffer, int32_t acquireFence) override; + Error setLayerCursorPosition(Display display, Layer layer, int32_t x, + int32_t y) override; + Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer, + int32_t acquireFence) override; Error setLayerSurfaceDamage(Display display, Layer layer, - const std::vector& damage) override; + const std::vector& damage) override; Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override; Error setLayerColor(Display display, Layer layer, - IComposerClient::Color color) override; + IComposerClient::Color color) override; Error setLayerCompositionType(Display display, Layer layer, - int32_t type) override; + int32_t type) override; Error setLayerDataspace(Display display, Layer layer, - int32_t dataspace) override; + int32_t dataspace) override; Error setLayerDisplayFrame(Display display, Layer layer, - const hwc_rect_t& frame) override; + const hwc_rect_t& frame) override; Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override; Error setLayerSidebandStream(Display display, Layer layer, - buffer_handle_t stream) override; + buffer_handle_t stream) override; Error setLayerSourceCrop(Display display, Layer layer, - const hwc_frect_t& crop) override; + const hwc_frect_t& crop) override; Error setLayerTransform(Display display, Layer layer, - int32_t transform) override; + int32_t transform) override; Error setLayerVisibleRegion(Display display, Layer layer, - const std::vector& visible) override; + const std::vector& visible) override; Error setLayerZOrder(Display display, Layer layer, uint32_t z) override; + // composer::V2_2::ComposerHal + Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle, + android::base::unique_fd fenceFd) override; + Error getReadbackBufferFence(Display display, + android::base::unique_fd* outFenceFd) override; + Error createVirtualDisplay_2_2(uint32_t width, uint32_t height, + types::V1_1::PixelFormat* format, + Display* outDisplay) override; + Error setPowerMode_2_2(Display display, + IComposerClient::PowerMode mode) override; + Error setLayerFloatColor(Display display, Layer layer, + IComposerClient::FloatColor color) override; + Error getRenderIntents(Display display, types::V1_1::ColorMode mode, + std::vector* outIntents) override; + std::array getDataspaceSaturationMatrix( + types::V1_1::Dataspace dataspace) override; + + // composer::V2_3::ComposerHal + Error getHdrCapabilities_2_3(Display display, hidl_vec* outTypes, + float* outMaxLuminance, + float* outMaxAverageLuminance, + float* outMinLuminance) override; + Error setLayerPerFrameMetadata_2_3( + Display display, Layer layer, + const std::vector& metadata) override; + Error getPerFrameMetadataKeys_2_3( + Display display, + std::vector* outKeys) override; + Error setColorMode_2_3(Display display, ColorMode mode, + RenderIntent intent) override; + Error getRenderIntents_2_3(Display display, ColorMode mode, + std::vector* outIntents) override; + Error getColorModes_2_3(Display display, + hidl_vec* outModes) override; + Error getClientTargetSupport_2_3(Display display, uint32_t width, + uint32_t height, PixelFormat format, + Dataspace dataspace) override; + Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat, + Dataspace* outDataspace) override; + Error getDisplayIdentificationData(Display display, uint8_t* outPort, + std::vector* outData) override; + Error setLayerColorTransform(Display display, Layer layer, + const float* matrix) override; + Error getDisplayedContentSamplingAttributes( + Display display, PixelFormat& format, Dataspace& dataspace, + hidl_bitfield& componentMask) + override; + Error setDisplayedContentSamplingEnabled( + Display display, IComposerClient::DisplayedContentSampling enable, + hidl_bitfield componentMask, + uint64_t maxFrames) override; + Error getDisplayedContentSample( + Display display, uint64_t maxFrames, uint64_t timestamp, + uint64_t& frameCount, hidl_vec& sampleComponent0, + hidl_vec& sampleComponent1, + hidl_vec& sampleComponent2, + hidl_vec& sampleComponent3) override; + Error getDisplayCapabilities(Display display, + std::vector* + outCapabilities) override; + Error setLayerPerFrameMetadataBlobs( + Display display, Layer layer, + std::vector& blobs) override; + Error getDisplayBrightnessSupport(Display display, bool* outSupport) override; + Error setDisplayBrightness(Display display, float brightness) override; + // IComposer: Return getCapabilities(getCapabilities_cb hidl_cb) override; Return dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; Return createClient(createClient_cb hidl_cb) override; + Return createClient_2_3( + IComposer::createClient_2_3_cb hidl_cb) override; // ComposerView: void ForceDisplaysRefresh() override; -- cgit v1.2.3-59-g8ed1b From daceef75545ccc041fc72582fba82625ac57f575 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 11 Jun 2019 13:49:19 -0700 Subject: libtimeinstate: support concurrent_{active,policy}_time Add support for querying and clearing stats for time each UID spent running concurrently with tasks on all other CPUs and on CPUs in the same cluster. Also add tests for the new functions, including consistency checks comparing time in state vs concurrent times. Finally, because the BPF program cannot update multiple map values atomically, userspace reads occasionally occur in between the updates to a UID's active and policy times. Add a check for this in our reader functions and retry once when it is detected. For the (very rare) case where the same race occurs when retrying, include a comment in our consistency test to help distinguish these transient failures from a more serious bug. Test: libtimeinstate_test passes Bug: 138317993 Change-Id: I429ed39d3ef82b6643fd042a74d9d403c658a8c1 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 165 +++++++++++++++++++++--- libs/cputimeinstate/cputimeinstate.h | 12 +- libs/cputimeinstate/testtimeinstate.cpp | 218 ++++++++++++++++++++++++++++++-- libs/cputimeinstate/timeinstate.h | 8 +- 4 files changed, 375 insertions(+), 28 deletions(-) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 4c8d52efd9..f255512704 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,8 @@ static uint32_t gNCpus = 0; static std::vector> gPolicyFreqs; static std::vector> gPolicyCpus; static std::set gAllFreqs; -static unique_fd gMapFd; +static unique_fd gTisMapFd; +static unique_fd gConcurrentMapFd; static std::optional> readNumbersFromFile(const std::string &path) { std::string data; @@ -122,8 +124,12 @@ static bool initGlobals() { gPolicyCpus.emplace_back(*cpus); } - gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; - if (gMapFd < 0) return false; + gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")}; + if (gTisMapFd < 0) return false; + + gConcurrentMapFd = + unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; + if (gConcurrentMapFd < 0) return false; gInitialized = true; return true; @@ -143,7 +149,7 @@ static bool attachTracepointProgram(const std::string &eventType, const std::str // process dies then it must be called again to resume tracking. // This function should *not* be called while tracking is already active; doing so is unnecessary // and can lead to accounting errors. -bool startTrackingUidCpuFreqTimes() { +bool startTrackingUidTimes() { if (!initGlobals()) return false; unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); @@ -174,7 +180,7 @@ bool startTrackingUidCpuFreqTimes() { attachTracepointProgram("power", "cpu_frequency"); } -// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes. +// Retrieve the times in ns that uid spent running at each CPU frequency. // Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], // [t1_0, t1_1, ...], ...] @@ -189,11 +195,11 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui out.emplace_back(freqList.size(), 0); } - std::vector vals(gNCpus); + std::vector vals(gNCpus); time_key_t key = {.uid = uid}; for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) { key.bucket = i; - if (findMapEntry(gMapFd, &key, vals.data())) { + if (findMapEntry(gTisMapFd, &key, vals.data())) { if (errno != ENOENT) return {}; continue; } @@ -214,7 +220,7 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui return out; } -// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap. +// Retrieve the times in ns that each uid spent running at each CPU freq. // Return contains no value on error, otherwise it contains a map from uids to vectors of vectors // using the format: // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...], @@ -225,7 +231,7 @@ getUidsCpuFreqTimes() { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map>> map; - if (getFirstMapKey(gMapFd, &key)) { + if (getFirstMapKey(gTisMapFd, &key)) { if (errno == ENOENT) return map; return std::nullopt; } @@ -233,9 +239,9 @@ getUidsCpuFreqTimes() { std::vector> mapFormat; for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); - std::vector vals(gNCpus); + std::vector vals(gNCpus); do { - if (findMapEntry(gMapFd, &key, vals.data())) return {}; + if (findMapEntry(gTisMapFd, &key, vals.data())) return {}; if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); auto offset = key.bucket * FREQS_PER_ENTRY; @@ -250,13 +256,129 @@ getUidsCpuFreqTimes() { } } prevKey = key; - } while (!getNextMapKey(gMapFd, &prevKey, &key)); + } while (!getNextMapKey(gTisMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; return map; } +static bool verifyConcurrentTimes(const concurrent_time_t &ct) { + uint64_t activeSum = std::accumulate(ct.active.begin(), ct.active.end(), (uint64_t)0); + uint64_t policySum = 0; + for (const auto &vec : ct.policy) { + policySum += std::accumulate(vec.begin(), vec.end(), (uint64_t)0); + } + return activeSum == policySum; +} + +// Retrieve the times in ns that uid spent running concurrently with each possible number of other +// tasks on each cluster (policy times) and overall (active times). +// Return contains no value on error, otherwise it contains a concurrent_time_t with the format: +// {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...]} +// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent +// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster +std::optional getUidConcurrentTimes(uint32_t uid, bool retry) { + if (!gInitialized && !initGlobals()) return {}; + concurrent_time_t ret = {.active = std::vector(gNCpus, 0)}; + for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0); + std::vector vals(gNCpus); + time_key_t key = {.uid = uid}; + for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) { + if (findMapEntry(gConcurrentMapFd, &key, vals.data())) { + if (errno != ENOENT) return {}; + continue; + } + auto offset = key.bucket * CPUS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY; + + auto activeBegin = ret.active.begin() + offset; + auto activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret.active.end(); + + for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) { + std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin, + std::plus()); + } + + for (uint32_t policy = 0; policy < gNPolicies; ++policy) { + if (offset >= gPolicyCpus[policy].size()) continue; + auto policyBegin = ret.policy[policy].begin() + offset; + auto policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY + : ret.policy[policy].end(); + + for (const auto &cpu : gPolicyCpus[policy]) { + std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, + std::plus()); + } + } + } + if (!verifyConcurrentTimes(ret) && retry) return getUidConcurrentTimes(uid, false); + return ret; +} + +// Retrieve the times in ns that each uid spent running concurrently with each possible number of +// other tasks on each cluster (policy times) and overall (active times). +// Return contains no value on error, otherwise it contains a map from uids to concurrent_time_t's +// using the format: +// { uid0 -> {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...] }, ...} +// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent +// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster. +std::optional> getUidsConcurrentTimes() { + if (!gInitialized && !initGlobals()) return {}; + time_key_t key, prevKey; + std::unordered_map ret; + if (getFirstMapKey(gConcurrentMapFd, &key)) { + if (errno == ENOENT) return ret; + return {}; + } + + concurrent_time_t retFormat = {.active = std::vector(gNCpus, 0)}; + for (const auto &cpuList : gPolicyCpus) retFormat.policy.emplace_back(cpuList.size(), 0); + + std::vector vals(gNCpus); + std::vector::iterator activeBegin, activeEnd, policyBegin, policyEnd; + + do { + if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {}; + if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat); + + auto offset = key.bucket * CPUS_PER_ENTRY; + auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY; + + activeBegin = ret[key.uid].active.begin(); + activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret[key.uid].active.end(); + + for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) { + std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin, + std::plus()); + } + + for (uint32_t policy = 0; policy < gNPolicies; ++policy) { + if (offset >= gPolicyCpus[policy].size()) continue; + policyBegin = ret[key.uid].policy[policy].begin() + offset; + policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY + : ret[key.uid].policy[policy].end(); + + for (const auto &cpu : gPolicyCpus[policy]) { + std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, + std::plus()); + } + } + prevKey = key; + } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key)); + if (errno != ENOENT) return {}; + for (const auto &[key, value] : ret) { + if (!verifyConcurrentTimes(value)) { + auto val = getUidConcurrentTimes(key, false); + if (val.has_value()) ret[key] = val.value(); + } + } + return ret; +} + // Clear all time in state data for a given uid. Returns false on error, true otherwise. -bool clearUidCpuFreqTimes(uint32_t uid) { +// This is only suitable for clearing data when an app is uninstalled; if called on a UID with +// running tasks it will cause time in state vs. concurrent time totals to be inconsistent for that +// UID. +bool clearUidTimes(uint32_t uid) { if (!gInitialized && !initGlobals()) return false; time_key_t key = {.uid = uid}; @@ -266,11 +388,20 @@ bool clearUidCpuFreqTimes(uint32_t uid) { if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size(); } - val_t zeros = {0}; - std::vector vals(gNCpus, zeros); + tis_val_t zeros = {0}; + std::vector vals(gNCpus, zeros); for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) { - if (writeToMapEntry(gMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) return false; - if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false; + if (writeToMapEntry(gTisMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT) + return false; + if (deleteMapEntry(gTisMapFd, &key) && errno != ENOENT) return false; + } + + concurrent_val_t czeros = {.policy = {0}, .active = {0}}; + std::vector cvals(gNCpus, czeros); + for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) { + if (writeToMapEntry(gConcurrentMapFd, &key, cvals.data(), BPF_EXIST) && errno != ENOENT) + return false; + if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false; } return true; } diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index d7b45870ac..f620715dab 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -22,11 +22,19 @@ namespace android { namespace bpf { -bool startTrackingUidCpuFreqTimes(); +bool startTrackingUidTimes(); std::optional>> getUidCpuFreqTimes(uint32_t uid); std::optional>>> getUidsCpuFreqTimes(); -bool clearUidCpuFreqTimes(unsigned int uid); + +struct concurrent_time_t { + std::vector active; + std::vector> policy; +}; + +std::optional getUidConcurrentTimes(uint32_t uid, bool retry = true); +std::optional> getUidsConcurrentTimes(); +bool clearUidTimes(unsigned int uid); } // namespace bpf } // namespace android diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 39007e4603..15f6214bff 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -3,6 +3,7 @@ #include +#include #include #include @@ -21,13 +22,83 @@ static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365; using std::vector; -TEST(TimeInStateTest, SingleUid) { +TEST(TimeInStateTest, SingleUidTimeInState) { auto times = getUidCpuFreqTimes(0); ASSERT_TRUE(times.has_value()); EXPECT_FALSE(times->empty()); } -TEST(TimeInStateTest, AllUid) { +TEST(TimeInStateTest, SingleUidConcurrentTimes) { + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + ASSERT_FALSE(concurrentTimes->active.empty()); + ASSERT_FALSE(concurrentTimes->policy.empty()); + + uint64_t policyEntries = 0; + for (const auto &policyTimeVec : concurrentTimes->policy) policyEntries += policyTimeVec.size(); + ASSERT_EQ(concurrentTimes->active.size(), policyEntries); +} + +static void TestConcurrentTimesConsistent(const struct concurrent_time_t &concurrentTime) { + size_t maxPolicyCpus = 0; + for (const auto &vec : concurrentTime.policy) { + maxPolicyCpus = std::max(maxPolicyCpus, vec.size()); + } + uint64_t policySum = 0; + for (size_t i = 0; i < maxPolicyCpus; ++i) { + for (const auto &vec : concurrentTime.policy) { + if (i < vec.size()) policySum += vec[i]; + } + ASSERT_LE(concurrentTime.active[i], policySum); + policySum -= concurrentTime.active[i]; + } + policySum = 0; + for (size_t i = 0; i < concurrentTime.active.size(); ++i) { + for (const auto &vec : concurrentTime.policy) { + if (i < vec.size()) policySum += vec[vec.size() - 1 - i]; + } + auto activeSum = concurrentTime.active[concurrentTime.active.size() - 1 - i]; + // This check is slightly flaky because we may read a map entry in the middle of an update + // when active times have been updated but policy times have not. This happens infrequently + // and can be distinguished from more serious bugs by re-running the test: if the underlying + // data itself is inconsistent, the test will fail every time. + ASSERT_LE(activeSum, policySum); + policySum -= activeSum; + } +} + +static void TestUidTimesConsistent(const std::vector> &timeInState, + const struct concurrent_time_t &concurrentTime) { + ASSERT_NO_FATAL_FAILURE(TestConcurrentTimesConsistent(concurrentTime)); + ASSERT_EQ(timeInState.size(), concurrentTime.policy.size()); + uint64_t policySum = 0; + for (uint32_t i = 0; i < timeInState.size(); ++i) { + uint64_t tisSum = + std::accumulate(timeInState[i].begin(), timeInState[i].end(), (uint64_t)0); + uint64_t concurrentSum = std::accumulate(concurrentTime.policy[i].begin(), + concurrentTime.policy[i].end(), (uint64_t)0); + if (tisSum < concurrentSum) + ASSERT_LE(concurrentSum - tisSum, NSEC_PER_SEC); + else + ASSERT_LE(tisSum - concurrentSum, NSEC_PER_SEC); + policySum += concurrentSum; + } + uint64_t activeSum = std::accumulate(concurrentTime.active.begin(), concurrentTime.active.end(), + (uint64_t)0); + EXPECT_EQ(activeSum, policySum); +} + +TEST(TimeInStateTest, SingleUidTimesConsistent) { + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + + ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes)); +} + +TEST(TimeInStateTest, AllUidTimeInState) { vector sizes; auto map = getUidsCpuFreqTimes(); ASSERT_TRUE(map.has_value()); @@ -43,7 +114,7 @@ TEST(TimeInStateTest, AllUid) { } } -TEST(TimeInStateTest, SingleAndAllUidConsistent) { +TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { auto map = getUidsCpuFreqTimes(); ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); @@ -64,6 +135,40 @@ TEST(TimeInStateTest, SingleAndAllUidConsistent) { } } +TEST(TimeInStateTest, AllUidConcurrentTimes) { + auto map = getUidsConcurrentTimes(); + ASSERT_TRUE(map.has_value()); + ASSERT_FALSE(map->empty()); + + auto firstEntry = map->begin()->second; + for (const auto &kv : *map) { + ASSERT_EQ(kv.second.active.size(), firstEntry.active.size()); + ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size()); + for (size_t i = 0; i < kv.second.policy.size(); ++i) { + ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size()); + } + } +} + +TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { + auto map = getUidsConcurrentTimes(); + ASSERT_TRUE(map.has_value()); + for (const auto &kv : *map) { + uint32_t uid = kv.first; + auto times1 = kv.second; + auto times2 = getUidConcurrentTimes(uid); + ASSERT_TRUE(times2.has_value()); + for (uint32_t i = 0; i < times1.active.size(); ++i) { + ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC); + } + for (uint32_t i = 0; i < times1.policy.size(); ++i) { + for (uint32_t j = 0; j < times1.policy[i].size(); ++j) { + ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC); + } + } + } +} + void TestCheckDelta(uint64_t before, uint64_t after) { // Times should never decrease ASSERT_LE(before, after); @@ -71,7 +176,7 @@ void TestCheckDelta(uint64_t before, uint64_t after) { ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf()); } -TEST(TimeInStateTest, AllUidMonotonic) { +TEST(TimeInStateTest, AllUidTimeInStateMonotonic) { auto map1 = getUidsCpuFreqTimes(); ASSERT_TRUE(map1.has_value()); sleep(1); @@ -92,7 +197,35 @@ TEST(TimeInStateTest, AllUidMonotonic) { } } -TEST(TimeInStateTest, AllUidSanityCheck) { +TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) { + auto map1 = getUidsConcurrentTimes(); + ASSERT_TRUE(map1.has_value()); + ASSERT_FALSE(map1->empty()); + sleep(1); + auto map2 = getUidsConcurrentTimes(); + ASSERT_TRUE(map2.has_value()); + ASSERT_FALSE(map2->empty()); + + for (const auto &kv : *map1) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(map2->find(uid), map2->end()); + for (uint32_t i = 0; i < times.active.size(); ++i) { + auto before = times.active[i]; + auto after = (*map2)[uid].active[i]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + for (uint32_t policy = 0; policy < times.policy.size(); ++policy) { + for (uint32_t idx = 0; idx < times.policy[policy].size(); ++idx) { + auto before = times.policy[policy][idx]; + auto after = (*map2)[uid].policy[policy][idx]; + ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after)); + } + } + } +} + +TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { auto map = getUidsCpuFreqTimes(); ASSERT_TRUE(map.has_value()); @@ -110,6 +243,48 @@ TEST(TimeInStateTest, AllUidSanityCheck) { ASSERT_TRUE(foundLargeValue); } +TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { + auto concurrentMap = getUidsConcurrentTimes(); + ASSERT_TRUE(concurrentMap); + + bool activeFoundLargeValue = false; + bool policyFoundLargeValue = false; + for (const auto &kv : *concurrentMap) { + for (const auto &time : kv.second.active) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) activeFoundLargeValue = true; + } + for (const auto &policyTimeVec : kv.second.policy) { + for (const auto &time : policyTimeVec) { + ASSERT_LE(time, NSEC_PER_YEAR); + if (time > UINT32_MAX) policyFoundLargeValue = true; + } + } + } + // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using + // uint64_t as expected, we should have some times higher than that. + ASSERT_TRUE(activeFoundLargeValue); + ASSERT_TRUE(policyFoundLargeValue); +} + +TEST(TimeInStateTest, AllUidTimesConsistent) { + auto tisMap = getUidsCpuFreqTimes(); + ASSERT_TRUE(tisMap.has_value()); + + auto concurrentMap = getUidsConcurrentTimes(); + ASSERT_TRUE(concurrentMap.has_value()); + + ASSERT_EQ(tisMap->size(), concurrentMap->size()); + for (const auto &kv : *tisMap) { + uint32_t uid = kv.first; + auto times = kv.second; + ASSERT_NE(concurrentMap->find(uid), concurrentMap->end()); + + auto concurrentTimes = (*concurrentMap)[uid]; + ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(times, concurrentTimes)); + } +} + TEST(TimeInStateTest, RemoveUid) { uint32_t uid = 0; { @@ -122,31 +297,58 @@ TEST(TimeInStateTest, RemoveUid) { } { // Add a map entry for our fake UID by copying a real map entry - android::base::unique_fd fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; + android::base::unique_fd fd{ + bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")}; ASSERT_GE(fd, 0); time_key_t k; ASSERT_FALSE(getFirstMapKey(fd, &k)); - std::vector vals(get_nprocs_conf()); + std::vector vals(get_nprocs_conf()); ASSERT_FALSE(findMapEntry(fd, &k, vals.data())); + uint32_t copiedUid = k.uid; k.uid = uid; ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST)); + + android::base::unique_fd fd2{ + bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; + k.uid = copiedUid; + k.bucket = 0; + std::vector cvals(get_nprocs_conf()); + ASSERT_FALSE(findMapEntry(fd2, &k, cvals.data())); + k.uid = uid; + ASSERT_FALSE(writeToMapEntry(fd2, &k, cvals.data(), BPF_NOEXIST)); } auto times = getUidCpuFreqTimes(uid); ASSERT_TRUE(times.has_value()); ASSERT_FALSE(times->empty()); + auto concurrentTimes = getUidConcurrentTimes(0); + ASSERT_TRUE(concurrentTimes.has_value()); + ASSERT_FALSE(concurrentTimes->active.empty()); + ASSERT_FALSE(concurrentTimes->policy.empty()); + uint64_t sum = 0; for (size_t i = 0; i < times->size(); ++i) { for (auto x : (*times)[i]) sum += x; } ASSERT_GT(sum, (uint64_t)0); - ASSERT_TRUE(clearUidCpuFreqTimes(uid)); + uint64_t activeSum = 0; + for (size_t i = 0; i < concurrentTimes->active.size(); ++i) { + activeSum += concurrentTimes->active[i]; + } + ASSERT_GT(activeSum, (uint64_t)0); + + ASSERT_TRUE(clearUidTimes(uid)); auto allTimes = getUidsCpuFreqTimes(); ASSERT_TRUE(allTimes.has_value()); ASSERT_FALSE(allTimes->empty()); ASSERT_EQ(allTimes->find(uid), allTimes->end()); + + auto allConcurrentTimes = getUidsConcurrentTimes(); + ASSERT_TRUE(allConcurrentTimes.has_value()); + ASSERT_FALSE(allConcurrentTimes->empty()); + ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end()); } } // namespace bpf diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h index 41d0af07a2..6d4f913f80 100644 --- a/libs/cputimeinstate/timeinstate.h +++ b/libs/cputimeinstate/timeinstate.h @@ -19,16 +19,22 @@ #define BPF_FS_PATH "/sys/fs/bpf/" #define FREQS_PER_ENTRY 32 +#define CPUS_PER_ENTRY 8 struct time_key_t { uint32_t uid; uint32_t bucket; }; -struct val_t { +struct tis_val_t { uint64_t ar[FREQS_PER_ENTRY]; }; +struct concurrent_val_t { + uint64_t active[CPUS_PER_ENTRY]; + uint64_t policy[CPUS_PER_ENTRY]; +}; + struct freq_idx_key_t { uint32_t policy; uint32_t freq; -- cgit v1.2.3-59-g8ed1b From b2b503075c682c5aca211d840bd06f97332cef00 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 28 Aug 2019 16:15:38 -0700 Subject: libtimeinstate: move map format info into shared header Switch from using timeinstate.h to a shared header in system/bpf that provides key & value struct definitions both to libtimeinstate and to our BPF program Test: build libtimeinstate Bug: 138317993 Change-Id: I302b40bd1dfa7b529888f598cf36c146400f1315 Signed-off-by: Connor O'Brien --- libs/cputimeinstate/Android.bp | 2 ++ libs/cputimeinstate/cputimeinstate.cpp | 2 +- libs/cputimeinstate/testtimeinstate.cpp | 2 +- libs/cputimeinstate/timeinstate.h | 41 --------------------------------- 4 files changed, 4 insertions(+), 43 deletions(-) delete mode 100644 libs/cputimeinstate/timeinstate.h (limited to 'libs') diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp index 9080ce13db..a8f7d92b41 100644 --- a/libs/cputimeinstate/Android.bp +++ b/libs/cputimeinstate/Android.bp @@ -8,6 +8,7 @@ cc_library { "liblog", "libnetdutils" ], + header_libs: ["bpf_prog_headers"], cflags: [ "-Werror", "-Wall", @@ -25,6 +26,7 @@ cc_test { "libtimeinstate", "libnetdutils", ], + header_libs: ["bpf_prog_headers"], cflags: [ "-Werror", "-Wall", diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index f255512704..2d2536c397 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -17,7 +17,7 @@ #define LOG_TAG "libtimeinstate" #include "cputimeinstate.h" -#include "timeinstate.h" +#include #include #include diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 15f6214bff..c0cd3e07ff 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -1,5 +1,5 @@ -#include "timeinstate.h" +#include #include diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h deleted file mode 100644 index 6d4f913f80..0000000000 --- a/libs/cputimeinstate/timeinstate.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#define BPF_FS_PATH "/sys/fs/bpf/" - -#define FREQS_PER_ENTRY 32 -#define CPUS_PER_ENTRY 8 - -struct time_key_t { - uint32_t uid; - uint32_t bucket; -}; - -struct tis_val_t { - uint64_t ar[FREQS_PER_ENTRY]; -}; - -struct concurrent_val_t { - uint64_t active[CPUS_PER_ENTRY]; - uint64_t policy[CPUS_PER_ENTRY]; -}; - -struct freq_idx_key_t { - uint32_t policy; - uint32_t freq; -}; -- cgit v1.2.3-59-g8ed1b From 067fcd36bc53a5f884108df5634cb1ca5549a30c Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 14 Aug 2019 10:41:12 -0700 Subject: libgui: Add discardFreeBuffers callback to producer This enables buffer producer to clear its buffer caches. Test: Camera CTS, libgui_test Bug: 136677409 Change-Id: I7f46e977f3edc3b08177654531745d8ca0b86889 --- libs/gui/BufferQueueConsumer.cpp | 10 ++- libs/gui/BufferQueueCore.cpp | 7 ++ libs/gui/BufferQueueProducer.cpp | 5 +- libs/gui/IProducerListener.cpp | 26 +++++++ libs/gui/Surface.cpp | 49 ++++++++++++ libs/gui/include/gui/BufferQueueCore.h | 6 +- libs/gui/include/gui/IProducerListener.h | 6 ++ libs/gui/include/gui/Surface.h | 44 +++++++++++ libs/gui/tests/BufferQueue_test.cpp | 28 ++++++- libs/gui/tests/Surface_test.cpp | 126 +++++++++++++++++++++++++++++++ 10 files changed, 299 insertions(+), 8 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 528bfb194e..3a7cb44450 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -166,7 +166,9 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, mCore->mFreeBuffers.push_back(front->mSlot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } ++numDroppedBuffers; } @@ -457,7 +459,9 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, mCore->mFreeBuffers.push_back(slot); } - listener = mCore->mConnectedProducerListener; + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } BQ_LOGV("releaseBuffer: releasing slot %d", slot); mCore->mDequeueCondition.notify_all(); @@ -668,7 +672,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; VALIDATE_CONSISTENCY(); - if (delta < 0) { + if (delta < 0 && mCore->mBufferReleasedCbEnabled) { listener = mCore->mConsumerListener; } } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index b429d387ad..d6009d6cd5 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -65,6 +65,7 @@ BufferQueueCore::BufferQueueCore() : mConnectedApi(NO_CONNECTED_API), mLinkedToDeath(), mConnectedProducerListener(), + mBufferReleasedCbEnabled(false), mSlots(), mQueue(), mFreeSlots(), @@ -264,6 +265,12 @@ void BufferQueueCore::freeAllBuffersLocked() { } void BufferQueueCore::discardFreeBuffersLocked() { + // Notify producer about the discarded buffers. + if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) { + std::vector freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end()); + mConnectedProducerListener->onBuffersDiscarded(freeBuffers); + } + for (int s : mFreeBuffers) { mFreeSlots.insert(s); clearBufferSlotLocked(s); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index d149674eeb..56746749b9 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1223,9 +1223,8 @@ status_t BufferQueueProducer::connect(const sp& listener, } mCore->mLinkedToDeath = listener; } - if (listener->needsReleaseNotify()) { - mCore->mConnectedProducerListener = listener; - } + mCore->mConnectedProducerListener = listener; + mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify(); } break; default: diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 936063a5bd..808e3369f1 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -24,6 +24,7 @@ namespace android { enum { ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION, NEEDS_RELEASE_NOTIFY, + ON_BUFFERS_DISCARDED, }; class BpProducerListener : public BpInterface @@ -56,6 +57,13 @@ public: } return result; } + + virtual void onBuffersDiscarded(const std::vector& discardedSlots) { + Parcel data, reply; + data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); + data.writeInt32Vector(discardedSlots); + remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -76,6 +84,10 @@ public: virtual bool needsReleaseNotify() override { return mBase->needsReleaseNotify(); } + + virtual void onBuffersDiscarded(const std::vector& discardedSlots) override { + return mBase->onBuffersDiscarded(discardedSlots); + } }; IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener, @@ -92,6 +104,17 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, CHECK_INTERFACE(IProducerListener, data, reply); reply->writeBool(needsReleaseNotify()); return NO_ERROR; + case ON_BUFFERS_DISCARDED: { + CHECK_INTERFACE(IProducerListener, data, reply); + std::vector discardedSlots; + status_t result = data.readInt32Vector(&discardedSlots); + if (result != NO_ERROR) { + ALOGE("ON_BUFFERS_DISCARDED failed to read discardedSlots: %d", result); + return result; + } + onBuffersDiscarded(discardedSlots); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -104,4 +127,7 @@ bool BnProducerListener::needsReleaseNotify() { return true; } +void BnProducerListener::onBuffersDiscarded(const std::vector& /*discardedSlots*/) { +} + } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index eb2e3f0615..7e356e4eb1 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -1299,6 +1300,14 @@ int Surface::connect(int api, const sp& listener) { return connect(api, listener, false); } +int Surface::connect( + int api, bool reportBufferRemoval, const sp& sListener) { + if (sListener != nullptr) { + mListenerProxy = new ProducerListenerProxy(this, sListener); + } + return connect(api, mListenerProxy, reportBufferRemoval); +} + int Surface::connect( int api, const sp& listener, bool reportBufferRemoval) { ATRACE_CALL(); @@ -1700,6 +1709,28 @@ void Surface::freeAllBuffers() { } } +status_t Surface::getAndFlushBuffersFromSlots(const std::vector& slots, + std::vector>* outBuffers) { + ALOGV("Surface::getAndFlushBuffersFromSlots"); + for (int32_t i : slots) { + if (i < 0 || i >= NUM_BUFFER_SLOTS) { + ALOGE("%s: Invalid slotIndex: %d", __FUNCTION__, i); + return BAD_VALUE; + } + } + + Mutex::Autolock lock(mMutex); + for (int32_t i : slots) { + if (mSlots[i].buffer == nullptr) { + ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i); + continue; + } + outBuffers->push_back(mSlots[i].buffer); + mSlots[i].buffer = nullptr; + } + return OK; +} + void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { ATRACE_CALL(); ALOGV("Surface::setSurfaceDamage"); @@ -1985,4 +2016,22 @@ int Surface::setAutoPrerotation(bool autoPrerotation) { return err; } +void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector& slots) { + ATRACE_CALL(); + sp parent = mParent.promote(); + if (parent == nullptr) { + return; + } + + std::vector> discardedBufs; + status_t res = parent->getAndFlushBuffersFromSlots(slots, &discardedBufs); + if (res != OK) { + ALOGE("%s: Failed to get buffers from slots: %s(%d)", __FUNCTION__, + strerror(-res), res); + return; + } + + mSurfaceListener->onBuffersDiscarded(discardedBufs); +} + }; // namespace android diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 205e79c879..3c960894da 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -189,8 +189,12 @@ private: sp mLinkedToDeath; // mConnectedProducerListener is used to handle the onBufferReleased - // notification. + // and onBuffersDiscarded notification. sp mConnectedProducerListener; + // mBufferReleasedCbEnabled is used to indicate whether onBufferReleased() + // callback is registered by the listener. When set to false, + // mConnectedProducerListener will not trigger onBufferReleased() callback. + bool mBufferReleasedCbEnabled; // mSlots is an array of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index a13d8e4945..32a3690ff2 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GUI_IPRODUCERLISTENER_H #define ANDROID_GUI_IPRODUCERLISTENER_H +#include + #include #include #include @@ -44,6 +46,9 @@ public: // multiple threads. virtual void onBufferReleased() = 0; // Asynchronous virtual bool needsReleaseNotify() = 0; + // onBuffersFreed is called from IGraphicBufferConsumer::discardFreeBuffers + // to notify the producer that certain free buffers are discarded by the consumer. + virtual void onBuffersDiscarded(const std::vector& slots) = 0; // Asynchronous }; class IProducerListener : public ProducerListener, public IInterface @@ -65,6 +70,7 @@ public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual bool needsReleaseNotify(); + virtual void onBuffersDiscarded(const std::vector& slots); }; class DummyProducerListener : public BnProducerListener diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index fe528b3711..28f5a26072 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,21 @@ namespace android { class ISurfaceComposer; +/* This is the same as ProducerListener except that onBuffersDiscarded is + * called with a vector of graphic buffers instead of buffer slots. + */ +class SurfaceListener : public virtual RefBase +{ +public: + SurfaceListener() = default; + virtual ~SurfaceListener() = default; + + virtual void onBufferReleased() = 0; + virtual bool needsReleaseNotify() = 0; + + virtual void onBuffersDiscarded(const std::vector>& buffers) = 0; +}; + /* * An implementation of ANativeWindow that feeds graphics buffers into a * BufferQueue. @@ -285,6 +301,10 @@ public: sp* outFence); virtual int attachBuffer(ANativeWindowBuffer*); + virtual int connect( + int api, bool reportBufferRemoval, + const sp& sListener); + // When client connects to Surface with reportBufferRemoval set to true, any buffers removed // from this Surface will be collected and returned here. Once this method returns, these // buffers will no longer be referenced by this Surface unless they are attached to this @@ -301,6 +321,26 @@ protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; + class ProducerListenerProxy : public BnProducerListener { + public: + ProducerListenerProxy(wp parent, sp listener) + : mParent(parent), mSurfaceListener(listener) {} + virtual ~ProducerListenerProxy() {} + + virtual void onBufferReleased() { + mSurfaceListener->onBufferReleased(); + } + + virtual bool needsReleaseNotify() { + return mSurfaceListener->needsReleaseNotify(); + } + + virtual void onBuffersDiscarded(const std::vector& slots); + private: + wp mParent; + sp mSurfaceListener; + }; + void querySupportedTimestampsLocked() const; void freeAllBuffers(); @@ -470,6 +510,10 @@ protected: bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; int mMaxBufferCount; + + sp mListenerProxy; + status_t getAndFlushBuffersFromSlots(const std::vector& slots, + std::vector>* outBuffers); }; } // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 98dc1e6337..6d7b6bb9c6 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -1010,12 +1010,31 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { ASSERT_EQ(true, thirdSegment.usedThirdBuffer); } +struct BufferDiscardedListener : public BnProducerListener { +public: + BufferDiscardedListener() = default; + virtual ~BufferDiscardedListener() = default; + + virtual void onBufferReleased() {} + virtual bool needsReleaseNotify() { return false; } + virtual void onBuffersDiscarded(const std::vector& slots) { + mDiscardedSlots.insert(mDiscardedSlots.end(), slots.begin(), slots.end()); + } + + const std::vector& getDiscardedSlots() const { return mDiscardedSlots; } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + std::vector mDiscardedSlots; +}; + TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { createBufferQueue(); sp dc(new DummyConsumer); ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false)); IGraphicBufferProducer::QueueBufferOutput output; - ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener, + sp pl(new BufferDiscardedListener); + ASSERT_EQ(OK, mProducer->connect(pl, NATIVE_WINDOW_API_CPU, false, &output)); int slot = BufferQueue::INVALID_BUFFER_SLOT; @@ -1056,12 +1075,19 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); + int releasedSlot = item.mSlot; + // Acquire 1 buffer, leaving 1 filled buffer in queue ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); // Now discard the free buffers ASSERT_EQ(OK, mConsumer->discardFreeBuffers()); + // Check onBuffersDiscarded is called with correct slots + auto buffersDiscarded = pl->getDiscardedSlots(); + ASSERT_EQ(buffersDiscarded.size(), 1); + ASSERT_EQ(buffersDiscarded[0], releasedSlot); + // Check no free buffers in dump String8 dumpString; mConsumer->dumpState(String8{}, &dumpString); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 7718bc1b8e..5a121d77ab 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -57,6 +57,37 @@ class FakeProducerFrameEventHistory; static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits::max(); +class DummySurfaceListener : public SurfaceListener { +public: + DummySurfaceListener(bool enableReleasedCb = false) : + mEnableReleaseCb(enableReleasedCb), + mBuffersReleased(0) {} + virtual ~DummySurfaceListener() = default; + + virtual void onBufferReleased() { + mBuffersReleased++; + } + virtual bool needsReleaseNotify() { + return mEnableReleaseCb; + } + virtual void onBuffersDiscarded(const std::vector>& buffers) { + mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end()); + } + + int getReleaseNotifyCount() const { + return mBuffersReleased; + } + const std::vector>& getDiscardedBuffers() const { + return mDiscardedBuffers; + } +private: + // No need to use lock given the test triggers the listener in the same + // thread context. + bool mEnableReleaseCb; + int32_t mBuffersReleased; + std::vector> mDiscardedBuffers; +}; + class SurfaceTest : public ::testing::Test { protected: SurfaceTest() { @@ -88,6 +119,86 @@ protected: mComposerClient->dispose(); } + void testSurfaceListener(bool hasSurfaceListener, bool enableReleasedCb, + int32_t extraDiscardedBuffers) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp surface = new Surface(producer); + sp window(surface); + sp listener; + if (hasSurfaceListener) { + listener = new DummySurfaceListener(enableReleasedCb); + } + ASSERT_EQ(OK, surface->connect( + NATIVE_WINDOW_API_CPU, + /*reportBufferRemoval*/true, + /*listener*/listener)); + const int BUFFER_COUNT = 4 + extraDiscardedBuffers; + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); + + ANativeWindowBuffer* buffers[BUFFER_COUNT]; + // Dequeue first to allocate a number of buffers + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffers[i])); + } + for (int i = 0; i < BUFFER_COUNT; i++) { + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], -1)); + } + + ANativeWindowBuffer* buffer; + // Fill BUFFER_COUNT-1 buffers + for (int i = 0; i < BUFFER_COUNT-1; i++) { + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, -1)); + } + + // Dequeue 1 buffer + ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer)); + + // Acquire and free 1+extraDiscardedBuffers buffer, check onBufferReleased is called. + std::vector releasedItems; + releasedItems.resize(1+extraDiscardedBuffers); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&releasedItems[i], 0)); + ASSERT_EQ(NO_ERROR, consumer->releaseBuffer(releasedItems[i].mSlot, + releasedItems[i].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, + Fence::NO_FENCE)); + } + int32_t expectedReleaseCb = (enableReleasedCb ? releasedItems.size() : 0); + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Acquire 1 buffer, leaving 1+extraDiscardedBuffers filled buffer in queue + BufferItem item; + ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&item, 0)); + + // Discard free buffers + ASSERT_EQ(NO_ERROR, consumer->discardFreeBuffers()); + + if (hasSurfaceListener) { + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + + // Check onBufferDiscarded is called with correct buffer + auto discardedBuffers = listener->getDiscardedBuffers(); + ASSERT_EQ(discardedBuffers.size(), releasedItems.size()); + for (int i = 0; i < releasedItems.size(); i++) { + ASSERT_EQ(discardedBuffers[i], releasedItems[i].mGraphicBuffer); + } + + ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount()); + } + + // Disconnect the surface + ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); + } + sp mSurface; sp mComposerClient; sp mSurfaceControl; @@ -480,6 +591,21 @@ TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) { ASSERT_LE(removedBuffers.size(), 1u); } +TEST_F(SurfaceTest, SurfaceListenerTest) { + // Test discarding 1 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with no listener + testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/0); + // Test discarding 2 free buffers with a listener, disabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/1); + // Test discarding 1 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/0); + // Test discarding 3 free buffers with a listener, enabling onBufferReleased + testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/2); +} + TEST_F(SurfaceTest, TestGetLastDequeueStartTime) { sp anw(mSurface); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU)); -- cgit v1.2.3-59-g8ed1b From 214c89db99f280cd67ca14357c9ee11adce0acce Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 4 Sep 2019 16:03:53 -0700 Subject: Remove setGeometryAppliesWithResize This function is no longer used so removing the API and any logic implemented for it. Test: go/wm-smoke Change-Id: I4ae2128cd38e818fcd16dafa4ce47c9411bd61c9 --- libs/gui/LayerState.cpp | 3 - libs/gui/SurfaceComposerClient.cpp | 13 --- libs/gui/include/gui/LayerState.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 6 - services/surfaceflinger/BufferQueueLayer.cpp | 2 +- services/surfaceflinger/BufferStateLayer.h | 4 +- services/surfaceflinger/Layer.cpp | 39 ++----- services/surfaceflinger/Layer.h | 6 +- services/surfaceflinger/LayerRejecter.cpp | 28 ++--- services/surfaceflinger/LayerRejecter.h | 12 +- services/surfaceflinger/RefreshRateOverlay.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- services/surfaceflinger/tests/Transaction_test.cpp | 124 --------------------- .../tests/fakehwc/SFFakeHwc_test.cpp | 18 --- 14 files changed, 32 insertions(+), 234 deletions(-) (limited to 'libs') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index be58b853d7..523ed1d2ce 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -291,9 +291,6 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eOverrideScalingModeChanged; overrideScalingMode = other.overrideScalingMode; } - if (other.what & eGeometryAppliesWithResize) { - what |= eGeometryAppliesWithResize; - } if (other.what & eReparentChildren) { what |= eReparentChildren; reparentHandle = other.reparentHandle; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5faf010d72..67dd726eba 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1187,19 +1187,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverr return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize( - const sp& sc) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eGeometryAppliesWithResize; - - registerSurfaceControlForCallback(sc); - return *this; -} - #ifndef NO_INPUT SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( const sp& sc, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index cbd1c8553b..2eb5492558 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -71,7 +71,7 @@ struct layer_state_t { eCropChanged_legacy = 0x00000100, eDeferTransaction_legacy = 0x00000200, eOverrideScalingModeChanged = 0x00000400, - eGeometryAppliesWithResize = 0x00000800, + // AVAILABLE 0x00000800, eReparentChildren = 0x00001000, eDetachChildren = 0x00002000, eRelativeLayerChanged = 0x00004000, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f303a03254..d65e679e24 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -446,12 +446,6 @@ public: Transaction& setOverrideScalingMode(const sp& sc, int32_t overrideScalingMode); - // If the size changes in this transaction, all geometry updates specified - // in this transaction will not complete until a buffer of the new size - // arrives. As some elements normally apply immediately, this enables - // freezing the total geometry of a surface until a resize is completed. - Transaction& setGeometryAppliesWithResize(const sp& sc); - #ifndef NO_INPUT Transaction& setInputWindowInfo(const sp& sc, const InputWindowInfo& info); Transaction& transferTouchFocus(const sp& fromToken, const sp& toToken); diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 5f494ff3d5..85a00fbe0d 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -276,7 +276,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t const int32_t layerID = getSequence(); LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions, getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode, - getTransformToDisplayInverse(), mFreezeGeometryUpdates); + getTransformToDisplayInverse()); if (isRemovedFromCurrentState()) { expectedPresentTime = 0; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index cc670087ac..f2a5dffe7c 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -82,13 +82,13 @@ public: // Override to ignore legacy layer state properties that are not used by BufferStateLayer bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } - bool setPosition(float /*x*/, float /*y*/, bool /*immediate*/) override { return false; } + bool setPosition(float /*x*/, float /*y*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/, bool /*allowNonRectPreservingTransforms*/) override { return false; } - bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; } + bool setCrop_legacy(const Rect& /*crop*/) override { return false; } bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; } void deferTransactionUntil_legacy(const sp& /*barrierHandle*/, uint64_t /*frameNumber*/) override {} diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5121835cae..4c8a6bf465 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -770,11 +770,6 @@ uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { if (!(flags & eDontUpdateGeometryState)) { State& editCurrentState(getCurrentState()); - // If mFreezeGeometryUpdates is true we are in the setGeometryAppliesWithResize - // mode, which causes attributes which normally latch regardless of scaling mode, - // to be delayed. We copy the requested state to the active state making sure - // to respect these rules (again see Layer.h for a detailed discussion). - // // There is an awkward asymmetry in the handling of the crop states in the position // states, as can be seen below. Largely this arises from position and transform // being stored in the same data structure while having different latching rules. @@ -782,16 +777,8 @@ uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) { // // Careful that "stateToCommit" and editCurrentState may not begin as equivalent due to // applyPendingStates in the presence of deferred transactions. - if (mFreezeGeometryUpdates) { - float tx = stateToCommit->active_legacy.transform.tx(); - float ty = stateToCommit->active_legacy.transform.ty(); - stateToCommit->active_legacy = stateToCommit->requested_legacy; - stateToCommit->active_legacy.transform.set(tx, ty); - editCurrentState.active_legacy = stateToCommit->active_legacy; - } else { - editCurrentState.active_legacy = editCurrentState.requested_legacy; - stateToCommit->active_legacy = stateToCommit->requested_legacy; - } + editCurrentState.active_legacy = editCurrentState.requested_legacy; + stateToCommit->active_legacy = stateToCommit->requested_legacy; } return flags; @@ -858,7 +845,7 @@ uint32_t Layer::setTransactionFlags(uint32_t flags) { return mTransactionFlags.fetch_or(flags); } -bool Layer::setPosition(float x, float y, bool immediate) { +bool Layer::setPosition(float x, float y) { if (mCurrentState.requested_legacy.transform.tx() == x && mCurrentState.requested_legacy.transform.ty() == y) return false; @@ -868,14 +855,11 @@ bool Layer::setPosition(float x, float y, bool immediate) { // we want to apply the position portion of the transform matrix immediately, // but still delay scaling when resizing a SCALING_MODE_FREEZE layer. mCurrentState.requested_legacy.transform.set(x, y); - if (immediate && !mFreezeGeometryUpdates) { - // Here we directly update the active state - // unlike other setters, because we store it within - // the transform, but use different latching rules. - // b/38182305 - mCurrentState.active_legacy.transform.set(x, y); - } - mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate; + // Here we directly update the active state + // unlike other setters, because we store it within + // the transform, but use different latching rules. + // b/38182305 + mCurrentState.active_legacy.transform.set(x, y); mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); @@ -1081,14 +1065,11 @@ bool Layer::setFlags(uint8_t flags, uint8_t mask) { return true; } -bool Layer::setCrop_legacy(const Rect& crop, bool immediate) { +bool Layer::setCrop_legacy(const Rect& crop) { if (mCurrentState.requestedCrop_legacy == crop) return false; mCurrentState.sequence++; mCurrentState.requestedCrop_legacy = crop; - if (immediate && !mFreezeGeometryUpdates) { - mCurrentState.crop_legacy = crop; - } - mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate; + mCurrentState.crop_legacy = crop; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9107189d52..a2409e79d2 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -268,9 +268,9 @@ public: // setPosition operates in parent buffer space (pre parent-transform) or display // space for top-level layers. - virtual bool setPosition(float x, float y, bool immediate); + virtual bool setPosition(float x, float y); // Buffer space - virtual bool setCrop_legacy(const Rect& crop, bool immediate); + virtual bool setCrop_legacy(const Rect& crop); // TODO(b/38182121): Could we eliminate the various latching modes by // using the layer hierarchy? @@ -860,8 +860,6 @@ protected: // This layer can be a cursor on some displays. bool mPotentialCursor{false}; - bool mFreezeGeometryUpdates{false}; - // Child list about to be committed/used for editing. LayerVector mCurrentChildren{LayerVector::StateSet::Current}; // Child list used for rendering. diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp index 72abea8b2d..8a221837ac 100644 --- a/services/surfaceflinger/LayerRejecter.cpp +++ b/services/surfaceflinger/LayerRejecter.cpp @@ -23,22 +23,16 @@ namespace android { -LayerRejecter::LayerRejecter(Layer::State& front, - Layer::State& current, - bool& recomputeVisibleRegions, - bool stickySet, - const char* name, - int32_t overrideScalingMode, - bool transformToDisplayInverse, - bool& freezePositionUpdates) - : mFront(front), - mCurrent(current), - mRecomputeVisibleRegions(recomputeVisibleRegions), - mStickyTransformSet(stickySet), - mName(name), - mOverrideScalingMode(overrideScalingMode), - mTransformToDisplayInverse(transformToDisplayInverse), - mFreezeGeometryUpdates(freezePositionUpdates) {} +LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current, + bool& recomputeVisibleRegions, bool stickySet, const char* name, + int32_t overrideScalingMode, bool transformToDisplayInverse) + : mFront(front), + mCurrent(current), + mRecomputeVisibleRegions(recomputeVisibleRegions), + mStickyTransformSet(stickySet), + mName(name), + mOverrideScalingMode(overrideScalingMode), + mTransformToDisplayInverse(transformToDisplayInverse) {} bool LayerRejecter::reject(const sp& buf, const BufferItem& item) { if (buf == nullptr) { @@ -83,8 +77,6 @@ bool LayerRejecter::reject(const sp& buf, const BufferItem& item) // recompute visible region mRecomputeVisibleRegions = true; - mFreezeGeometryUpdates = false; - if (mFront.crop_legacy != mFront.requestedCrop_legacy) { mFront.crop_legacy = mFront.requestedCrop_legacy; mCurrent.crop_legacy = mFront.requestedCrop_legacy; diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h index 63d51de0ca..1bd0c26dc6 100644 --- a/services/surfaceflinger/LayerRejecter.h +++ b/services/surfaceflinger/LayerRejecter.h @@ -23,14 +23,9 @@ namespace android { class LayerRejecter : public BufferLayerConsumer::BufferRejecter { public: - LayerRejecter(Layer::State &front, - Layer::State ¤t, - bool &recomputeVisibleRegions, - bool stickySet, - const char *name, - int32_t overrideScalingMode, - bool transformToDisplayInverse, - bool &freezePositionUpdates); + LayerRejecter(Layer::State &front, Layer::State ¤t, bool &recomputeVisibleRegions, + bool stickySet, const char *name, int32_t overrideScalingMode, + bool transformToDisplayInverse); virtual bool reject(const sp &buf, const BufferItem &item); @@ -42,7 +37,6 @@ namespace android { const char *mName; int32_t mOverrideScalingMode; bool mTransformToDisplayInverse; - bool &mFreezeGeometryUpdates; }; } // namespace android diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 5b4bec96ea..976fedb58a 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -39,7 +39,7 @@ bool RefreshRateOverlay::createLayer() { Mutex::Autolock _l(mFlinger.mStateLock); mLayer = mClient->getLayerUser(mIBinder); - mLayer->setCrop_legacy(Rect(50, 70, 200, 100), true); + mLayer->setCrop_legacy(Rect(50, 70, 200, 100)); // setting Layer's Z requires resorting layersSortedByZ ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7a8eb6b2da..c1a8f87d37 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3597,8 +3597,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( uint32_t flags = 0; const uint64_t what = s.what; - bool geometryAppliesWithResize = - what & layer_state_t::eGeometryAppliesWithResize; // If we are deferring transaction, make sure to push the pending state, as otherwise the // pending state will also be deferred. @@ -3607,7 +3605,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( } if (what & layer_state_t::ePositionChanged) { - if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) { + if (layer->setPosition(s.x, s.y)) { flags |= eTraversalNeeded; } } @@ -3698,8 +3696,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } if (what & layer_state_t::eCropChanged_legacy) { - if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize)) - flags |= eTraversalNeeded; + if (layer->setCrop_legacy(s.crop_legacy)) flags |= eTraversalNeeded; } if (what & layer_state_t::eCornerRadiusChanged) { if (layer->setCornerRadius(s.cornerRadius)) diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index b1fde22e0e..03c646b0bb 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -842,62 +842,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) { } } -TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // request setPosition to be applied with the next resize - Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply(); - { - SCOPED_TRACE("new position pending"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setPosition(layer, 15, 20).apply(); - { - SCOPED_TRACE("pending new position modified"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setSize(layer, 64, 64).apply(); - { - SCOPED_TRACE("resize pending"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - // finally resize and latch the buffer - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("new position applied"); - getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED); - } -} - -TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setPosition is not immediate even with SCALE_TO_WINDOW override - Transaction() - .setPosition(layer, 5, 10) - .setSize(layer, 64, 64) - .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) - .setGeometryAppliesWithResize(layer) - .apply(); - { - SCOPED_TRACE("new position pending"); - getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED); - } - - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64)); - { - SCOPED_TRACE("new position applied"); - getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); @@ -2310,74 +2254,6 @@ TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) { } } -TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // request setCrop_legacy to be applied with the next resize - Transaction() - .setCrop_legacy(layer, Rect(8, 8, 24, 24)) - .setGeometryAppliesWithResize(layer) - .apply(); - { - SCOPED_TRACE("waiting for next resize"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply(); - { - SCOPED_TRACE("pending crop modified"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - Transaction().setSize(layer, 16, 16).apply(); - { - SCOPED_TRACE("resize pending"); - getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); - } - - // finally resize - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); - { - SCOPED_TRACE("new crop applied"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(4, 4, 12, 12), Color::RED); - shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); - } -} - -TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) { - sp layer; - ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32)); - - // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override - Transaction() - .setCrop_legacy(layer, Rect(4, 4, 12, 12)) - .setSize(layer, 16, 16) - .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) - .setGeometryAppliesWithResize(layer) - .apply(); - { - SCOPED_TRACE("new crop pending"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(0, 0, 16, 16), Color::RED); - shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK); - } - - // XXX crop is never latched without other geometry change (b/69315677) - Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply(); - ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16)); - Transaction().setPosition(layer, 0, 0).apply(); - { - SCOPED_TRACE("new crop applied"); - auto shot = getScreenCapture(); - shot->expectColor(Rect(4, 4, 12, 12), Color::RED); - shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK); - } -} - TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) { sp layer; ASSERT_NO_FATAL_FAILURE( diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index a892a2abd0..093bcf576d 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1331,16 +1331,6 @@ TEST_F(LatchingTest, SurfacePositionLatching) { restoreInitialState(); - // Now we repeat with setGeometryAppliesWithResize - // and verify the position DOESN'T latch. - { - TransactionScope ts(*sFakeComposer); - ts.setGeometryAppliesWithResize(mFGSurfaceControl); - ts.setSize(mFGSurfaceControl, 32, 32); - ts.setPosition(mFGSurfaceControl, 100, 100); - } - EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); - completeFGResize(); auto referenceFrame2 = mBaseFrame; @@ -1365,14 +1355,6 @@ TEST_F(LatchingTest, CropLatching) { restoreInitialState(); - { - TransactionScope ts(*sFakeComposer); - ts.setSize(mFGSurfaceControl, 128, 128); - ts.setGeometryAppliesWithResize(mFGSurfaceControl); - ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63)); - } - EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame())); - completeFGResize(); auto referenceFrame2 = mBaseFrame; -- cgit v1.2.3-59-g8ed1b From 0d1398b2da8aee028c52a90be6d3b75b4f12b9d6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 14 Aug 2019 10:53:50 -0700 Subject: [ANativeWindow] Add apex header for getLastQueueDuration Bug: 137012798 Test: libnativewindow_test Change-Id: I46d5ab9c11161923ebbbc67400b10b2e7c0c6b61 --- libs/nativewindow/ANativeWindow.cpp | 4 +++ libs/nativewindow/include/apex/window.h | 8 ++++++ libs/nativewindow/libnativewindow.map.txt | 1 + libs/nativewindow/tests/ANativeWindowTest.cpp | 35 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+) (limited to 'libs') diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 4c59e6ce98..5c91d587bc 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -274,3 +274,7 @@ int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { return query(window, NATIVE_WINDOW_LAST_DEQUEUE_DURATION); } + +int ANativeWindow_getLastQueueDuration(ANativeWindow* window) { + return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION); +} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 0260cbcfb4..82ff50d2d5 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -31,4 +31,12 @@ __BEGIN_DECLS */ int ANativeWindow_getLastDequeueDuration(ANativeWindow* window); +/** + * Retrieves how long it took for the last time a buffer was queued. + * + * \return a negative value on error, otherwise returns the duration in + * microseconds + */ +int ANativeWindow_getLastQueueDuration(ANativeWindow* window); + __END_DECLS diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 7fe4df0606..b8b45ae62b 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -23,6 +23,7 @@ LIBNATIVEWINDOW { ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getLastDequeueDuration; # apex # introduced=30 + ANativeWindow_getLastQueueDuration; # apex # introduced=30 ANativeWindow_getWidth; ANativeWindow_lock; ANativeWindow_query; # vndk diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 5247e04c32..9b358da4b5 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -36,6 +36,9 @@ public: // Exposes the internal last dequeue duration that's stored on the Surface. nsecs_t getLastDequeueDuration() const { return mLastDequeueDuration; } + + // Exposes the internal last queue duration that's stored on the Surface. + nsecs_t getLastQueueDuration() const { return mLastQueueDuration; } }; class ANativeWindowTest : public ::testing::Test { @@ -82,3 +85,35 @@ TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { EXPECT_GT(result, 0); EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000); } + +TEST_F(ANativeWindowTest, getLastQueueDuration_noDequeue_returnsZero) { + int result = ANativeWindow_getLastQueueDuration(mWindow.get()); + EXPECT_EQ(0, result); + EXPECT_EQ(0, mWindow->getLastQueueDuration()); +} + +TEST_F(ANativeWindowTest, getLastQueueDuration_noQueue_returnsZero) { + ANativeWindowBuffer* buffer; + int fd; + int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, result); + + result = ANativeWindow_getLastQueueDuration(mWindow.get()); + EXPECT_EQ(result, 0); + EXPECT_EQ(result, mWindow->getLastQueueDuration()); +} + +TEST_F(ANativeWindowTest, getLastQueueDuration_withQueue_returnsTime) { + ANativeWindowBuffer* buffer; + int fd; + int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, result); + + result = ANativeWindow_queueBuffer(mWindow.get(), buffer, 0); + + result = ANativeWindow_getLastQueueDuration(mWindow.get()); + EXPECT_GT(result, 0); + EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000); +} -- cgit v1.2.3-59-g8ed1b From a161966a658f46f8bec93ea0490bef799843c3c6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 21 Aug 2019 19:30:48 -0700 Subject: [ANativeWindow] Add apex stub for getLastDequeueStartTime Also adding private query64 hook so that timing queries can have nanosecond precision. Otherwise with a 32-bit width we can only have millisecond precision for timestamps and microsecond precision for time intervals, and really we shouldn't need to be less precise if we can help it. Bug: 137012798 Test: libnativewindow_test Change-Id: I62233a588eee80f7ea70b74824c8e47461a3be81 --- libs/gui/Surface.cpp | 14 +++++++++----- libs/gui/include/gui/Surface.h | 4 +--- libs/gui/tests/Surface_test.cpp | 2 +- libs/nativewindow/ANativeWindow.cpp | 6 ++++++ libs/nativewindow/include/apex/window.h | 9 +++++++++ libs/nativewindow/include/system/window.h | 2 +- libs/nativewindow/libnativewindow.map.txt | 1 + libs/nativewindow/tests/ANativeWindowTest.cpp | 21 +++++++++++++++++++++ 8 files changed, 49 insertions(+), 10 deletions(-) (limited to 'libs') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 7e356e4eb1..aad18491b4 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1081,6 +1081,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_AUTO_PREROTATION: res = dispatchSetAutoPrerotation(args); break; + case NATIVE_WINDOW_GET_LAST_DEQUEUE_START: + res = dispatchGetLastDequeueStartTime(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1286,6 +1289,12 @@ int Surface::dispatchSetAutoPrerotation(va_list args) { return setAutoPrerotation(autoPrerotation); } +int Surface::dispatchGetLastDequeueStartTime(va_list args) { + int64_t* lastDequeueStartTime = va_arg(args, int64_t*); + *lastDequeueStartTime = mLastDequeueStartTime; + return NO_ERROR; +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -1950,11 +1959,6 @@ int Surface::getConsumerUsage(uint64_t* outUsage) const { return mGraphicBufferProducer->getConsumerUsage(outUsage); } -nsecs_t Surface::getLastDequeueStartTime() const { - Mutex::Autolock lock(mMutex); - return mLastDequeueStartTime; -} - status_t Surface::getAndFlushRemovedBuffers(std::vector>* out) { if (out == nullptr) { ALOGE("%s: out must not be null!", __FUNCTION__); diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 28f5a26072..5bcfcda6ad 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -179,9 +179,6 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call - nsecs_t getLastDequeueStartTime() const; - protected: virtual ~Surface(); @@ -247,6 +244,7 @@ private: int dispatchGetHdrSupport(va_list args); int dispatchGetConsumerUsage64(va_list args); int dispatchSetAutoPrerotation(va_list args); + int dispatchGetLastDequeueStartTime(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 5a121d77ab..0b61d9231c 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -617,7 +617,7 @@ TEST_F(SurfaceTest, TestGetLastDequeueStartTime) { anw->dequeueBuffer(anw.get(), &buffer, &fenceFd); nsecs_t after = systemTime(CLOCK_MONOTONIC); - nsecs_t lastDequeueTime = mSurface->getLastDequeueStartTime(); + nsecs_t lastDequeueTime = ANativeWindow_getLastDequeueStartTime(anw.get()); ASSERT_LE(before, lastDequeueTime); ASSERT_GE(after, lastDequeueTime); } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 5c91d587bc..3b195f7913 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -278,3 +278,9 @@ int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { int ANativeWindow_getLastQueueDuration(ANativeWindow* window) { return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION); } + +int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { + int64_t time; + int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time); + return success < 0 ? success : time; +} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 82ff50d2d5..3ddd5493ac 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -39,4 +39,13 @@ int ANativeWindow_getLastDequeueDuration(ANativeWindow* window); */ int ANativeWindow_getLastQueueDuration(ANativeWindow* window); +/** + * Retrieves the system time in nanoseconds when the last time a buffer + * was dequeued. + * + * \return a negative value on error, otherwise returns the duration in + * nanoseconds. + */ +int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); + __END_DECLS diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 78354bba6b..b7ae28a93c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -93,7 +93,6 @@ enum { */ NATIVE_WINDOW_CONCRETE_TYPE = 5, - /* * Default width and height of ANativeWindow buffers, these are the * dimensions of the window buffers irrespective of the @@ -240,6 +239,7 @@ enum { NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, + NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */ // clang-format on }; diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index b8b45ae62b..33c6400d52 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -23,6 +23,7 @@ LIBNATIVEWINDOW { ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getLastDequeueDuration; # apex # introduced=30 + ANativeWindow_getLastDequeueStartTime; # apex # introduced=30 ANativeWindow_getLastQueueDuration; # apex # introduced=30 ANativeWindow_getWidth; ANativeWindow_lock; diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 9b358da4b5..947217d52c 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -39,6 +39,9 @@ public: // Exposes the internal last queue duration that's stored on the Surface. nsecs_t getLastQueueDuration() const { return mLastQueueDuration; } + + // Exposes the internal last dequeue start time that's stored on the Surface. + nsecs_t getLastDequeueStartTime() const { return mLastDequeueStartTime; } }; class ANativeWindowTest : public ::testing::Test { @@ -117,3 +120,21 @@ TEST_F(ANativeWindowTest, getLastQueueDuration_withQueue_returnsTime) { EXPECT_GT(result, 0); EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000); } + +TEST_F(ANativeWindowTest, getLastDequeueStartTime_noDequeue_returnsZero) { + int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get()); + EXPECT_EQ(0, result); + EXPECT_EQ(0, mWindow->getLastQueueDuration()); +} + +TEST_F(ANativeWindowTest, getLastDequeueStartTime_withDequeue_returnsTime) { + ANativeWindowBuffer* buffer; + int fd; + int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, dequeueResult); + + int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get()); + EXPECT_GT(result, 0); + EXPECT_EQ(result, mWindow->getLastDequeueStartTime()); +} -- cgit v1.2.3-59-g8ed1b From 04fdb60d01038d4d1e82b4c71f9bd3e9c74cb031 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 23 Aug 2019 19:41:43 -0700 Subject: [ANativeWindow] Add stub for ANativeWindow_setDequeueTimeout HWUI and media both require setting a dequeue timeout so that dequeue calls don't hang. Bug: 137012798 Test: libnativewindow_test Change-Id: Ic85b07096d490918ae4a722516b8c4b6cb0ab678 --- libs/gui/Surface.cpp | 8 ++++++++ libs/gui/include/gui/Surface.h | 1 + libs/nativewindow/ANativeWindow.cpp | 4 ++++ libs/nativewindow/include/apex/window.h | 9 +++++++++ libs/nativewindow/include/system/window.h | 1 + libs/nativewindow/libnativewindow.map.txt | 1 + libs/nativewindow/tests/ANativeWindowTest.cpp | 28 +++++++++++++++++++++++++++ 7 files changed, 52 insertions(+) (limited to 'libs') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index aad18491b4..fb9d7427d7 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1084,6 +1084,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_DEQUEUE_START: res = dispatchGetLastDequeueStartTime(args); break; + case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT: + res = dispatchSetDequeueTimeout(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1295,6 +1298,11 @@ int Surface::dispatchGetLastDequeueStartTime(va_list args) { return NO_ERROR; } +int Surface::dispatchSetDequeueTimeout(va_list args) { + nsecs_t timeout = va_arg(args, int64_t); + return setDequeueTimeout(timeout); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 5bcfcda6ad..2527ec0a75 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -245,6 +245,7 @@ private: int dispatchGetConsumerUsage64(va_list args); int dispatchSetAutoPrerotation(va_list args); int dispatchGetLastDequeueStartTime(va_list args); + int dispatchSetDequeueTimeout(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 3b195f7913..fecfa193df 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -284,3 +284,7 @@ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time); return success < 0 ? success : time; } + +int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) { + return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, timeout); +} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 3ddd5493ac..9798c2fd47 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -48,4 +48,13 @@ int ANativeWindow_getLastQueueDuration(ANativeWindow* window); */ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); +/** + * Sets a timeout in nanoseconds for dequeue calls. All subsequent dequeue calls + * made by the window will return -ETIMEDOUT after the timeout if the dequeue + * takes too long. + * + * \return NO_ERROR on succes, -errno on error. + */ +int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout); + __END_DECLS diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index b7ae28a93c..8f850070b6 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -240,6 +240,7 @@ enum { NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */ + NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */ // clang-format on }; diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 33c6400d52..b741faa11f 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -40,6 +40,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersGeometry; ANativeWindow_setBuffersTimestamp; # vndk ANativeWindow_setBuffersTransform; + ANativeWindow_setDequeueTimeout; # apex # introduced=30 ANativeWindow_setSharedBufferMode; # vndk ANativeWindow_setSwapInterval; # vndk ANativeWindow_setUsage; # vndk diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 947217d52c..4d2b8c8f3b 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -138,3 +138,31 @@ TEST_F(ANativeWindowTest, getLastDequeueStartTime_withDequeue_returnsTime) { EXPECT_GT(result, 0); EXPECT_EQ(result, mWindow->getLastDequeueStartTime()); } + +TEST_F(ANativeWindowTest, setDequeueTimeout_causesDequeueTimeout) { + nsecs_t timeout = milliseconds_to_nanoseconds(100); + int result = ANativeWindow_setDequeueTimeout(mWindow.get(), timeout); + EXPECT_EQ(0, result); + + // The two dequeues should not timeout... + ANativeWindowBuffer* buffer; + int fd; + int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, dequeueResult); + int queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1); + EXPECT_EQ(0, queueResult); + dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + close(fd); + EXPECT_EQ(0, dequeueResult); + queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1); + EXPECT_EQ(0, queueResult); + + // ...but the third one should since the queue depth is too deep. + nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC); + dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd); + nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC); + close(fd); + EXPECT_EQ(TIMED_OUT, dequeueResult); + EXPECT_GE(end - start, timeout); +} -- cgit v1.2.3-59-g8ed1b From 72670c57aa1a158ab05055d65a618307d57bf154 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 31 Aug 2019 01:54:33 -0700 Subject: [ANativeWindow] Increase precision for duration queries. Use perform() instead in query() to retrieve dequeue/queue durations for nanosecond resolution. Bug: 137012798 Test: atest Change-Id: I894a8784f3321d4ab6f538d7e7fc1457de26f289 --- libs/gui/Surface.cpp | 18 ++++++++++++++++++ libs/gui/include/gui/Surface.h | 2 ++ libs/nativewindow/ANativeWindow.cpp | 18 +++++++++++------- libs/nativewindow/include/apex/window.h | 8 ++++---- libs/nativewindow/include/system/window.h | 12 +++++++++--- libs/nativewindow/tests/ANativeWindowTest.cpp | 6 +++--- 6 files changed, 47 insertions(+), 17 deletions(-) (limited to 'libs') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index fb9d7427d7..e490d6d17d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1087,6 +1087,12 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT: res = dispatchSetDequeueTimeout(args); break; + case NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION: + res = dispatchGetLastDequeueDuration(args); + break; + case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION: + res = dispatchGetLastQueueDuration(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1303,6 +1309,18 @@ int Surface::dispatchSetDequeueTimeout(va_list args) { return setDequeueTimeout(timeout); } +int Surface::dispatchGetLastDequeueDuration(va_list args) { + int64_t* lastDequeueDuration = va_arg(args, int64_t*); + *lastDequeueDuration = mLastDequeueDuration; + return NO_ERROR; +} + +int Surface::dispatchGetLastQueueDuration(va_list args) { + int64_t* lastQueueDuration = va_arg(args, int64_t*); + *lastQueueDuration = mLastQueueDuration; + return NO_ERROR; +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 2527ec0a75..e582509b6e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -246,6 +246,8 @@ private: int dispatchSetAutoPrerotation(va_list args); int dispatchGetLastDequeueStartTime(va_list args); int dispatchSetDequeueTimeout(va_list args); + int dispatchGetLastDequeueDuration(va_list args); + int dispatchGetLastQueueDuration(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index fecfa193df..0ba01f4da4 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -33,6 +33,12 @@ static int32_t query(ANativeWindow* window, int what) { return res < 0 ? res : value; } +static int64_t query64(ANativeWindow* window, int what) { + int64_t value; + int res = window->perform(window, what, &value); + return res < 0 ? res : value; +} + static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) { bool supported = false; switch (dataSpace) { @@ -271,18 +277,16 @@ int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation * apex-stable **************************************************************************************************/ -int ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { - return query(window, NATIVE_WINDOW_LAST_DEQUEUE_DURATION); +int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window) { + return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION); } -int ANativeWindow_getLastQueueDuration(ANativeWindow* window) { - return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION); +int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window) { + return query64(window, NATIVE_WINDOW_GET_LAST_QUEUE_DURATION); } int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) { - int64_t time; - int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time); - return success < 0 ? success : time; + return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START); } int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) { diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 9798c2fd47..869b22ec19 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -27,17 +27,17 @@ __BEGIN_DECLS * Retrieves how long it took for the last time a buffer was dequeued. * * \return a negative value on error, otherwise returns the duration in - * microseconds. + * nanoseconds */ -int ANativeWindow_getLastDequeueDuration(ANativeWindow* window); +int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window); /** * Retrieves how long it took for the last time a buffer was queued. * * \return a negative value on error, otherwise returns the duration in - * microseconds + * nanoseconds. */ -int ANativeWindow_getLastQueueDuration(ANativeWindow* window); +int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window); /** * Retrieves the system time in nanoseconds when the last time a buffer diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 8f850070b6..1814ab5568 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -63,9 +63,9 @@ __BEGIN_DECLS /* attributes queriable with query() */ enum { - NATIVE_WINDOW_WIDTH = 0, - NATIVE_WINDOW_HEIGHT = 1, - NATIVE_WINDOW_FORMAT = 2, + NATIVE_WINDOW_WIDTH = 0, + NATIVE_WINDOW_HEIGHT = 1, + NATIVE_WINDOW_FORMAT = 2, /* see ANativeWindowQuery in vndk/window.h */ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS, @@ -147,11 +147,15 @@ enum { /* * Returns the duration of the last dequeueBuffer call in microseconds + * Deprecated: please use NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION in + * perform() instead, which supports nanosecond precision. */ NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14, /* * Returns the duration of the last queueBuffer call in microseconds + * Deprecated: please use NATIVE_WINDOW_GET_LAST_QUEUE_DURATION in + * perform() instead, which supports nanosecond precision. */ NATIVE_WINDOW_LAST_QUEUE_DURATION = 15, @@ -241,6 +245,8 @@ enum { NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */ NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */ + NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */ // clang-format on }; diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp index 4d2b8c8f3b..6cf8291da2 100644 --- a/libs/nativewindow/tests/ANativeWindowTest.cpp +++ b/libs/nativewindow/tests/ANativeWindowTest.cpp @@ -74,7 +74,7 @@ protected: TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) { int result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_EQ(0, result); - EXPECT_EQ(0, mWindow->getLastDequeueDuration() / 1000); + EXPECT_EQ(0, mWindow->getLastDequeueDuration()); } TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { @@ -86,7 +86,7 @@ TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) { result = ANativeWindow_getLastDequeueDuration(mWindow.get()); EXPECT_GT(result, 0); - EXPECT_EQ(result, mWindow->getLastDequeueDuration() / 1000); + EXPECT_EQ(result, mWindow->getLastDequeueDuration()); } TEST_F(ANativeWindowTest, getLastQueueDuration_noDequeue_returnsZero) { @@ -118,7 +118,7 @@ TEST_F(ANativeWindowTest, getLastQueueDuration_withQueue_returnsTime) { result = ANativeWindow_getLastQueueDuration(mWindow.get()); EXPECT_GT(result, 0); - EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000); + EXPECT_EQ(result, mWindow->getLastQueueDuration()); } TEST_F(ANativeWindowTest, getLastDequeueStartTime_noDequeue_returnsZero) { -- cgit v1.2.3-59-g8ed1b From 3a64e7433553171a1708aa4a4d1ecf2d5cb845fd Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 5 Sep 2019 14:40:46 -0700 Subject: libbinder: -= unimplemented readRequestHeaders. This symbol isn't defined. Bug: N/A Test: N/A Change-Id: Ia43d6dae61a0cac314a0ec012d44cb97b0bd0135 --- libs/binder/include/binder/Parcel.h | 1 - 1 file changed, 1 deletion(-) (limited to 'libs') diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index db6854e47a..b1b8ff18f4 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -384,7 +384,6 @@ public: // Returns the work source provided by the caller. This can only be trusted for trusted calling // uid. uid_t readCallingWorkSourceUid() const; - void readRequestHeaders() const; private: typedef void (*release_func)(Parcel* parcel, -- cgit v1.2.3-59-g8ed1b From c326a94d15828aee6a9261763bb40b82824f0c6c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 9 Sep 2019 16:07:52 -0700 Subject: libbinder: Hide AppOpsManager/Service from vendor. Vendor apps can still use these behind stable SDK or NDK APIs as applicable, but native code on the vendor image can't use these APIs because they are using /dev/vndbinder and have an incompatible copy of libbinder. Since no vendor binary is serving this, removing extra pound defines and making the vendor version of this library slightly smaller. Bug: 124524556 Test: builds (no vendor code has added dependencies on this yet) Change-Id: Idf01641d4b340ca6fe33c181969507ec071ef930 --- libs/binder/Android.bp | 2 ++ libs/binder/AppOpsManager.cpp | 13 ------------- libs/binder/IAppOpsService.cpp | 4 ---- libs/binder/include/binder/AppOpsManager.h | 8 ++++---- libs/binder/include/binder/IAppOpsService.h | 13 ++++--------- 5 files changed, 10 insertions(+), 30 deletions(-) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 6ece4a2162..86f19c5873 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -86,8 +86,10 @@ cc_library_shared { vendor: { exclude_srcs: [ "ActivityManager.cpp", + "AppOpsManager.cpp", "IActivityManager.cpp", "IAppOpsCallback.cpp", + "IAppOpsService.cpp", "IBatteryStats.cpp", "IMediaResourceMonitor.cpp", "IPermissionController.cpp", diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp index e2af01c161..711fed96a1 100644 --- a/libs/binder/AppOpsManager.cpp +++ b/libs/binder/AppOpsManager.cpp @@ -32,7 +32,6 @@ namespace android { namespace { -#ifndef __ANDROID_VNDK__ #if defined(__BRILLO__) // Because Brillo has no application model, security policy is managed // statically (at build time) with SELinux controls. @@ -41,17 +40,13 @@ const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED; #else const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED; #endif // defined(__BRILLO__) -#endif // __ANDROID_VNDK__ } // namespace static String16 _appops("appops"); -#ifndef __ANDROID_VNDK__ static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER; -#endif // __ANDROID_VNDK__ static sp gToken; -#ifndef __ANDROID_VNDK__ static const sp& getToken(const sp& service) { pthread_mutex_lock(&gTokenMutex); if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) { @@ -60,17 +55,12 @@ static const sp& getToken(const sp& service) { pthread_mutex_unlock(&gTokenMutex); return gToken; } -#endif // __ANDROID_VNDK__ thread_local uint64_t notedAppOpsInThisBinderTransaction[2]; thread_local int32_t uidOfThisBinderTransaction = -1; // Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note -#ifndef __ANDROID_VNDK__ uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0}; -#else -uint8_t appOpsToNote[128] = {0}; -#endif // __ANDROID_VNDK__ AppOpsManager::AppOpsManager() { @@ -108,7 +98,6 @@ sp AppOpsManager::getService() } #endif // defined(__BRILLO__) -#ifndef __ANDROID_VNDK__ int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) { sp service = getService(); @@ -200,8 +189,6 @@ void AppOpsManager::setCameraAudioRestriction(int32_t mode) { } } -#endif // __ANDROID_VNDK__ - bool AppOpsManager::shouldCollectNotes(int32_t opcode) { sp service = getService(); if (service != nullptr) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index b6360cbffd..c58ea029b3 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -34,7 +34,6 @@ public: { } -#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); @@ -145,7 +144,6 @@ public: remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply); } -#endif virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) { Parcel data, reply; @@ -195,7 +193,6 @@ status_t BnAppOpsService::onTransact( { //printf("AppOpsService received: "); data.print(); switch(code) { -#ifndef __ANDROID_VNDK__ case CHECK_OPERATION_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); @@ -288,7 +285,6 @@ status_t BnAppOpsService::onTransact( reply->writeNoException(); return NO_ERROR; } break; -#endif // __ANDROID_VNDK__ case NOTE_ASYNC_OP_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); String16 callingPackageName = data.readString16(); diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index dff4d49596..f5a54cea4c 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -21,6 +21,10 @@ #include +#ifdef __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif + // --------------------------------------------------------------------------- namespace android { @@ -33,7 +37,6 @@ public: MODE_ERRORED = IAppOpsService::MODE_ERRORED }; -#ifndef __ANDROID_VNDK__ enum { OP_NONE = -1, OP_COARSE_LOCATION = 0, @@ -121,11 +124,9 @@ public: OP_READ_DEVICE_IDENTIFIERS = 89, _NUM_OP = 90 }; -#endif // __ANDROID_VNDK__ AppOpsManager(); -#ifndef __ANDROID_VNDK__ int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage); int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, const String16& callingPackage); @@ -145,7 +146,6 @@ public: void stopWatchingMode(const sp& callback); int32_t permissionToOpCode(const String16& permission); void setCameraAudioRestriction(int32_t mode); -#endif // __ANDROID_VNDK__ void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message); diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index 009ef6c7a7..978400304e 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -18,11 +18,13 @@ #ifndef ANDROID_IAPP_OPS_SERVICE_H #define ANDROID_IAPP_OPS_SERVICE_H -#ifndef __ANDROID_VNDK__ #include -#endif #include +#ifdef __ANDROID_VNDK__ +#error "This header is not visible to vendors" +#endif + namespace android { // ---------------------------------------------------------------------- @@ -32,7 +34,6 @@ class IAppOpsService : public IInterface public: DECLARE_META_INTERFACE(AppOpsService) -#ifndef __ANDROID_VNDK__ virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0; virtual int32_t startOperation(const sp& token, int32_t code, int32_t uid, @@ -47,13 +48,11 @@ public: virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid, const String16& packageName) = 0; virtual void setCameraAudioRestriction(int32_t mode) = 0; -#endif // __ANDROID_VNDK__ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName, int32_t opCode, const String16& message) = 0; virtual bool shouldCollectNotes(int32_t opCode) = 0; enum { -#ifndef __ANDROID_VNDK__ CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1, START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2, @@ -63,13 +62,9 @@ public: GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7, CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8, -#endif // __ANDROID_VNDK__ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9, SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10, -#ifndef __ANDROID_VNDK__ SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11, -#endif // __ANDROID_VNDK__ - }; enum { -- cgit v1.2.3-59-g8ed1b From d6f1fc25ee57327a262064a87bb4a4396ba12860 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Tue, 10 Sep 2019 14:29:20 -0700 Subject: Add layerStack field to DisplayInfo screenrecord utility requires display layer stack in order to record external displays. Bug: 140814450 Bug: 136165419 Test: screenrecord --display-id Change-Id: I1ec562e4df2db684eb9f216bd4439bb267a7d3e3 --- libs/ui/include/ui/DisplayInfo.h | 5 ++++- services/surfaceflinger/DisplayDevice.h | 7 ++----- services/surfaceflinger/SurfaceFlinger.cpp | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'libs') diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h index 8976d2d584..07722104de 100644 --- a/libs/ui/include/ui/DisplayInfo.h +++ b/libs/ui/include/ui/DisplayInfo.h @@ -24,6 +24,8 @@ namespace android { +constexpr uint32_t NO_LAYER_STACK = static_cast(-1); + struct DisplayInfo { uint32_t w{0}; uint32_t h{0}; @@ -37,6 +39,7 @@ struct DisplayInfo { nsecs_t presentationDeadline{0}; uint32_t viewportW{0}; uint32_t viewportH{0}; + uint32_t layerStack{NO_LAYER_STACK}; }; /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */ @@ -47,6 +50,6 @@ enum { DISPLAY_ORIENTATION_270 = 3 }; -}; // namespace android +} // namespace android #endif // ANDROID_COMPOSER_DISPLAY_INFO_H diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 52773204b9..ce4e1e6b09 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -65,10 +66,6 @@ public: constexpr static float sDefaultMinLumiance = 0.0; constexpr static float sDefaultMaxLumiance = 500.0; - enum { - NO_LAYER_STACK = 0xFFFFFFFF, - }; - explicit DisplayDevice(DisplayDeviceCreationArgs&& args); virtual ~DisplayDevice(); @@ -201,7 +198,7 @@ struct DisplayDeviceState { int32_t sequenceId = sNextSequenceId++; std::optional displayId; sp surface; - uint32_t layerStack = DisplayDevice::NO_LAYER_STACK; + uint32_t layerStack = NO_LAYER_STACK; Rect viewport; Rect frame; uint8_t orientation = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4361a94e64..cc34f50a58 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -874,11 +874,15 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, info.viewportW = uint32_t(viewport.getWidth()); info.viewportH = uint32_t(viewport.getHeight()); } + info.layerStack = display->getLayerStack(); } else { // TODO: where should this value come from? static const int TV_DENSITY = 213; info.density = TV_DENSITY / 160.0f; info.orientation = 0; + + const auto display = getDisplayDeviceLocked(displayToken); + info.layerStack = display->getLayerStack(); } info.xdpi = xdpi; -- cgit v1.2.3-59-g8ed1b From 0802618f60366e69bbbf4277d83e9c6f6aa473d6 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Thu, 12 Sep 2019 15:01:28 +0100 Subject: Replace libnativeloader-dummy-headers with libnativeloader-headers The libnativeloader-dummy-headers target has been deprecated in favour of the more appropriately named by otherwise identical libnativeloader-headers Test: m checkbuild Change-Id: I0d4018734f91a7da68d4c730f3c5bfb65c163ab8 --- libs/graphicsenv/Android.bp | 2 +- vulkan/libvulkan/Android.bp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp index f11cf62e50..642c5f2cc0 100644 --- a/libs/graphicsenv/Android.bp +++ b/libs/graphicsenv/Android.bp @@ -33,7 +33,7 @@ cc_library_shared { ], header_libs: [ - "libnativeloader-dummy-headers", + "libnativeloader-headers", ], export_include_dirs: ["include"], diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp index 651c94d896..83a52506fc 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -75,7 +75,7 @@ cc_library_shared { header_libs: [ "hwvulkan_headers", - "libnativeloader-dummy-headers", + "libnativeloader-headers", "vulkan_headers", ], export_header_lib_headers: ["vulkan_headers"], -- cgit v1.2.3-59-g8ed1b From 82353e993cd4889a231a0b2d243dccc98e323395 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 12 Sep 2019 12:38:47 -0700 Subject: Changed BufferLayer's canReceiveInput to check if its hidden by policy WM does not consider window size or alpha value when setting it as the focused window. However, SF will check if the window has a buffer and that its alpha is not 0. Because of this difference, Input Dispatcher will not be able to send input to the window while WM thinks the window is focused. This will cause apps to stop responding. While we define what the intended behavior should be, this fix reverts to previous behavior in P. Bug: 139494112 Test: adb shell monkey 10000; make sure monkey does not get stuck Test: check test app from can receive input b/140478820 Change-Id: I4160b49161dd1780713980707a5c911034f414b5 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 4 ++++ services/surfaceflinger/ContainerLayer.cpp | 4 ---- services/surfaceflinger/ContainerLayer.h | 2 -- services/surfaceflinger/Layer.cpp | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'libs') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 386f731d23..2ab34da5ec 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -435,6 +435,9 @@ TEST_F(InputSurfacesTest, input_ignores_transparent_region) { surface->expectTap(1, 1); } +/** + * TODO(b/139494112) fix tests once we define expected behavior + * // Ensure we send the input to the right surface when the surface visibility changes due to the // first buffer being submitted. ref: b/120839715 TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) { @@ -486,6 +489,7 @@ TEST_F(InputSurfacesTest, input_respects_color_layer_alpha) { injectTap(11, 11); bgSurface->expectTap(1, 1); } +*/ TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) { std::unique_ptr bgSurface = makeSurface(100, 100); diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp index d40a38c811..4a1130365a 100644 --- a/services/surfaceflinger/ContainerLayer.cpp +++ b/services/surfaceflinger/ContainerLayer.cpp @@ -30,8 +30,4 @@ bool ContainerLayer::isVisible() const { return false; } -bool ContainerLayer::canReceiveInput() const { - return !isHiddenByPolicy(); -} - } // namespace android diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h index f0fbb6104f..c3624f6d7d 100644 --- a/services/surfaceflinger/ContainerLayer.h +++ b/services/surfaceflinger/ContainerLayer.h @@ -31,8 +31,6 @@ public: const char* getType() const override { return "ContainerLayer"; } bool isVisible() const override; - bool canReceiveInput() const override; - bool isCreatedFromMainThread() const override { return true; } }; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 79ee827f0d..d117c1bb70 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2020,7 +2020,7 @@ std::shared_ptr Layer::getCompositionLayer() const { } bool Layer::canReceiveInput() const { - return isVisible(); + return !isHiddenByPolicy(); } compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( -- cgit v1.2.3-59-g8ed1b From 913cc1303cb856dd2e0cebc5a94b69a571fd81f9 Mon Sep 17 00:00:00 2001 From: mamik Date: Fri, 13 Sep 2019 14:58:43 -0700 Subject: EDID support for external display hotplug The hardware_composer caches the edid when a new hotplug event fires (connected and disconnected). The display services uses this cached edid when the edid is requested. Bug: 141007548 Test: Manual, ran on mtp device with wave optics plugged in and unplugged and verified edid with: "adb shell dumpsys SurfaceFlinger --display-id" Change-Id: I4556e1d8a3f8677b1d9301d9afbc40d514c86e27 --- libs/vr/libvrflinger/display_service.cpp | 26 +++++++++----------------- libs/vr/libvrflinger/display_service.h | 5 ----- libs/vr/libvrflinger/hardware_composer.cpp | 19 +++++++++++++++++++ libs/vr/libvrflinger/hardware_composer.h | 14 ++++++++++++++ 4 files changed, 42 insertions(+), 22 deletions(-) (limited to 'libs') diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp index 5a9360c2ae..582fed3a4a 100644 --- a/libs/vr/libvrflinger/display_service.cpp +++ b/libs/vr/libvrflinger/display_service.cpp @@ -18,6 +18,8 @@ #include #include +#include "DisplayHardware/DisplayIdentification.h" + using android::dvr::display::DisplayProtocol; using android::pdx::Channel; using android::pdx::ErrorStatus; @@ -44,19 +46,6 @@ DisplayService::DisplayService(Hwc2::Composer* hidl, Endpoint::Create(display::DisplayProtocol::kClientPath)) { hardware_composer_.Initialize( hidl, primary_display_id, request_display_callback); - - uint8_t port; - const auto error = hidl->getDisplayIdentificationData( - primary_display_id, &display_identification_port_, - &display_identification_data_); - if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { - if (error != - android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { - ALOGI("DisplayService: identification data error\n"); - } else { - ALOGI("DisplayService: identification data unsupported\n"); - } - } } bool DisplayService::IsInitialized() const { @@ -212,6 +201,7 @@ Status DisplayService::OnGetMetrics( pdx::Status DisplayService::OnGetConfigurationData( pdx::Message& /*message*/, display::ConfigFileType config_type) { std::string property_name; + DisplayIdentificationData display_identification_data; switch (config_type) { case display::ConfigFileType::kLensMetrics: property_name = kDvrLensMetricsProperty; @@ -223,11 +213,13 @@ pdx::Status DisplayService::OnGetConfigurationData( property_name = kDvrDeviceConfigProperty; break; case display::ConfigFileType::kDeviceEdid: - if (display_identification_data_.size() == 0) { + display_identification_data = + hardware_composer_.GetCurrentDisplayIdentificationData(); + if (display_identification_data.size() == 0) { return ErrorStatus(ENOENT); } - return std::string(display_identification_data_.begin(), - display_identification_data_.end()); + return std::string(display_identification_data.begin(), + display_identification_data.end()); default: return ErrorStatus(EINVAL); } @@ -246,7 +238,7 @@ pdx::Status DisplayService::OnGetConfigurationData( pdx::Status DisplayService::OnGetDisplayIdentificationPort( pdx::Message& /*message*/) { - return display_identification_port_; + return hardware_composer_.GetCurrentDisplayPort(); } // Creates a new DisplaySurface and associates it with this channel. This may diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h index 06ba566d32..89f1eaee33 100644 --- a/libs/vr/libvrflinger/display_service.h +++ b/libs/vr/libvrflinger/display_service.h @@ -18,8 +18,6 @@ #include "epoll_event_dispatcher.h" #include "hardware_composer.h" -#include "DisplayHardware/DisplayIdentification.h" - namespace android { namespace dvr { @@ -120,9 +118,6 @@ class DisplayService : public pdx::ServiceBase { DisplayService(const DisplayService&) = delete; void operator=(const DisplayService&) = delete; - - DisplayIdentificationData display_identification_data_; - uint8_t display_identification_port_; }; } // namespace dvr diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp index 9072d89d76..67607af6c4 100644 --- a/libs/vr/libvrflinger/hardware_composer.cpp +++ b/libs/vr/libvrflinger/hardware_composer.cpp @@ -137,6 +137,20 @@ HardwareComposer::~HardwareComposer(void) { composer_callback_->SetVsyncService(nullptr); } +void HardwareComposer::UpdateEdidData(Hwc2::Composer* composer, + hwc2_display_t hw_id) { + const auto error = composer->getDisplayIdentificationData( + hw_id, &display_port_, &display_identification_data_); + if (error != android::hardware::graphics::composer::V2_1::Error::NONE) { + if (error != + android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) { + ALOGI("hardware_composer: identification data error\n"); + } else { + ALOGI("hardware_composer: identification data unsupported\n"); + } + } +} + bool HardwareComposer::Initialize( Hwc2::Composer* composer, hwc2_display_t primary_display_id, RequestDisplayCallback request_display_callback) { @@ -164,6 +178,8 @@ bool HardwareComposer::Initialize( "HardwareComposer: Failed to create interrupt event fd : %s", strerror(errno)); + UpdateEdidData(composer, primary_display_id); + post_thread_ = std::thread(&HardwareComposer::PostThread, this); initialized_ = true; @@ -988,6 +1004,9 @@ bool HardwareComposer::UpdateTargetDisplay() { EnableDisplay(*external_display_, false); } + // Update the cached edid data for the current display. + UpdateEdidData(composer_.get(), target_display_->id); + // Turn the new target display on. EnableDisplay(*target_display_, true); diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h index db0d6a7670..989ce3588d 100644 --- a/libs/vr/libvrflinger/hardware_composer.h +++ b/libs/vr/libvrflinger/hardware_composer.h @@ -25,6 +25,7 @@ #include #include +#include "DisplayHardware/DisplayIdentification.h" #include "acquired_buffer.h" #include "display_surface.h" @@ -334,6 +335,14 @@ class HardwareComposer { int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer); void OnDeletedGlobalBuffer(DvrGlobalBufferKey key); + // Gets the edid data for the current active display (internal or external) + DisplayIdentificationData GetCurrentDisplayIdentificationData() { + return display_identification_data_; + } + + // Gets the edid port for the current active display (internal or external) + uint8_t GetCurrentDisplayPort() { return display_port_; } + private: DisplayParams GetDisplayParams(Hwc2::Composer* composer, hwc2_display_t display, bool is_primary); @@ -544,6 +553,11 @@ class HardwareComposer { bool vsync_trace_parity_ = false; sp vsync_service_; + // Edid section. + void UpdateEdidData(Hwc2::Composer* composer, hwc2_display_t hw_id); + DisplayIdentificationData display_identification_data_; + uint8_t display_port_; + static constexpr int kPostThreadInterrupted = 1; HardwareComposer(const HardwareComposer&) = delete; -- cgit v1.2.3-59-g8ed1b From 6cbb97591535868d629a562dfd7d8e24865cf551 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 5 Sep 2019 16:38:18 +0800 Subject: Revert "Fix drag and drop (2/3)" This reverts commit fbe5d9c4233dcd802a122f70ca5a3641fcd556ca. Bug: 137819199 Test: manual Change-Id: I7afec569519b9c69eb03225672db6db141b20241 --- include/input/IInputFlinger.h | 4 +-- libs/gui/tests/EndToEndNativeInputTest.cpp | 50 ------------------------------ libs/input/IInputFlinger.cpp | 17 ---------- services/inputflinger/InputManager.cpp | 4 --- services/inputflinger/InputManager.h | 1 - services/inputflinger/host/InputFlinger.h | 1 - services/surfaceflinger/SurfaceFlinger.cpp | 15 +-------- services/surfaceflinger/SurfaceFlinger.h | 1 - 8 files changed, 2 insertions(+), 91 deletions(-) (limited to 'libs') diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h index 4365a3c4e3..d23e3b7767 100644 --- a/include/input/IInputFlinger.h +++ b/include/input/IInputFlinger.h @@ -37,7 +37,6 @@ public: virtual void setInputWindows(const std::vector& inputHandles, const sp& setInputWindowsListener) = 0; - virtual void transferTouchFocus(const sp& fromToken, const sp& toToken) = 0; virtual void registerInputChannel(const sp& channel) = 0; virtual void unregisterInputChannel(const sp& channel) = 0; }; @@ -51,8 +50,7 @@ public: enum { SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, REGISTER_INPUT_CHANNEL_TRANSACTION, - UNREGISTER_INPUT_CHANNEL_TRANSACTION, - TRANSFER_TOUCH_FOCUS + UNREGISTER_INPUT_CHANNEL_TRANSACTION }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 386f731d23..f158e566e6 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -133,27 +133,6 @@ public: EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction()); } - void expectMotionEvent(int motionEventType, int x, int y) { - InputEvent *ev = consumeEvent(); - ASSERT_NE(ev, nullptr); - ASSERT_EQ(ev->getType(), AINPUT_EVENT_TYPE_MOTION); - MotionEvent *mev = static_cast(ev); - EXPECT_EQ(motionEventType, mev->getAction()); - EXPECT_EQ(x, mev->getX(0)); - EXPECT_EQ(y, mev->getY(0)); - } - - void expectNoMotionEvent(int motionEventType) { - InputEvent *ev = consumeEvent(); - if (ev == nullptr || ev->getType() != AINPUT_EVENT_TYPE_MOTION) { - // Didn't find an event or a motion event so assume action didn't occur. - return; - } - - MotionEvent *mev = static_cast(ev); - EXPECT_NE(motionEventType, mev->getAction()); - } - ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel); } @@ -278,15 +257,6 @@ void injectTap(int x, int y) { } } -void injectMotionEvent(std::string event, int x, int y) { - char *buf1, *buf2; - asprintf(&buf1, "%d", x); - asprintf(&buf2, "%d", y); - if (fork() == 0) { - execlp("input", "input", "motionevent", event.c_str(), buf1, buf2, NULL); - } -} - TEST_F(InputSurfacesTest, can_receive_input) { std::unique_ptr surface = makeSurface(100, 100); surface->showAt(100, 100); @@ -504,26 +474,6 @@ TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) { bgSurface->expectTap(1, 1); } -TEST_F(InputSurfacesTest, transfer_touch_focus) { - std::unique_ptr fromSurface = makeSurface(100, 100); - - fromSurface->showAt(10, 10); - injectMotionEvent("DOWN", 11, 11); - fromSurface->expectMotionEvent(AMOTION_EVENT_ACTION_DOWN, 1, 1); - - std::unique_ptr toSurface = makeSurface(100, 100); - toSurface->showAt(10, 10); - - sp fromToken = fromSurface->mServerChannel->getToken(); - sp toToken = toSurface->mServerChannel->getToken(); - SurfaceComposerClient::Transaction t; - t.transferTouchFocus(fromToken, toToken).apply(true); - - injectMotionEvent("UP", 11, 11); - toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1); - fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP); -} - TEST_F(InputSurfacesTest, input_respects_outscreen) { std::unique_ptr surface = makeSurface(100, 100); surface->showAt(-1, -1); diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp index 90f6e09a69..8ec51653a8 100644 --- a/libs/input/IInputFlinger.cpp +++ b/libs/input/IInputFlinger.cpp @@ -45,16 +45,6 @@ public: IBinder::FLAG_ONEWAY); } - virtual void transferTouchFocus(const sp& fromToken, const sp& toToken) { - Parcel data, reply; - data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); - - data.writeStrongBinder(fromToken); - data.writeStrongBinder(toToken); - remote()->transact(BnInputFlinger::TRANSFER_TOUCH_FOCUS, data, &reply, - IBinder::FLAG_ONEWAY); - } - virtual void registerInputChannel(const sp& channel) { Parcel data, reply; data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); @@ -102,13 +92,6 @@ status_t BnInputFlinger::onTransact( unregisterInputChannel(channel); break; } - case TRANSFER_TOUCH_FOCUS: { - CHECK_INTERFACE(IInputFlinger, data, reply); - sp fromToken = data.readStrongBinder(); - sp toToken = data.readStrongBinder(); - transferTouchFocus(fromToken, toToken); - break; - } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 3996cca646..acb53be69e 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -117,10 +117,6 @@ void InputManager::setInputWindows(const std::vector& infos, } } -void InputManager::transferTouchFocus(const sp& fromToken, const sp& toToken) { - mDispatcher->transferTouchFocus(fromToken, toToken); -} - // Used by tests only. void InputManager::registerInputChannel(const sp& channel) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index e568df54df..32f7ae0058 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -96,7 +96,6 @@ public: virtual void setInputWindows(const std::vector& handles, const sp& setInputWindowsListener); - virtual void transferTouchFocus(const sp& fromToken, const sp& toToken); virtual void registerInputChannel(const sp& channel); virtual void unregisterInputChannel(const sp& channel); diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h index d8b352cbc6..973b4f92fa 100644 --- a/services/inputflinger/host/InputFlinger.h +++ b/services/inputflinger/host/InputFlinger.h @@ -42,7 +42,6 @@ public: virtual status_t dump(int fd, const Vector& args); void setInputWindows(const std::vector&, const sp&) {} - void transferTouchFocus(const sp&, const sp&) {} void registerInputChannel(const sp&) {} void unregisterInputChannel(const sp&) {} diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3498419cdf..a35426e8d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2606,7 +2606,7 @@ void SurfaceFlinger::updateInputFlinger() { setInputWindowsFinished(); } - executeInputWindowCommands(); + mInputWindowCommands.clear(); } void SurfaceFlinger::updateInputWindowInfo() { @@ -2630,19 +2630,6 @@ void SurfaceFlinger::commitInputWindowCommands() { mPendingInputWindowCommands.clear(); } -void SurfaceFlinger::executeInputWindowCommands() { - for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) { - if (transferTouchFocusCommand.fromToken != nullptr && - transferTouchFocusCommand.toToken != nullptr && - transferTouchFocusCommand.fromToken != transferTouchFocusCommand.toToken) { - mInputFlinger->transferTouchFocus(transferTouchFocusCommand.fromToken, - transferTouchFocusCommand.toToken); - } - } - - mInputWindowCommands.clear(); -} - void SurfaceFlinger::updateCursorAsync() { compositionengine::CompositionRefreshArgs refreshArgs; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f220c26bdf..e0259c80ec 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -551,7 +551,6 @@ private: void updateInputFlinger(); void updateInputWindowInfo(); void commitInputWindowCommands() REQUIRES(mStateLock); - void executeInputWindowCommands(); void setInputWindowsFinished(); void updateCursorAsync(); -- cgit v1.2.3-59-g8ed1b From acb7299dfc8e9270923141183bbde04b135e8492 Mon Sep 17 00:00:00 2001 From: Ytai Ben-Tsvi Date: Thu, 5 Sep 2019 15:14:30 -0700 Subject: Improve visibility of IMemory security risks This change renames the IMemory raw pointer accessors to unsecure*() to make it apparent to coders and code reviewers that the returned buffer may potentially be shared with untrusted processes, who may, after the fact, attempt to read and/or modify the contents. This may lead to hard to find security bugs and hopefully the rename makes it harder to forget. The change also attempts to fix all the callsites to make everything build correctly, but in the processes, wherever the callsite code was not obviously secure, I added a TODO requesting the owners to either document why it's secure or to change the code. Apologies in advance to the owners if there are some false positives here - I don't have enough context to reason about all the different callsites. Test: Completely syntactic change. Made sure code still builds. Change-Id: If8474d0c6a2f0a23cb0514eac1a86c71e334fcc9 --- libs/binder/IMemory.cpp | 4 +++- libs/binder/include/binder/IMemory.h | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index caf2318281..a7662e9fd2 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -149,7 +149,7 @@ void* IMemory::fastPointer(const sp& binder, ssize_t offset) const return static_cast(base) + offset; } -void* IMemory::pointer() const { +void* IMemory::unsecurePointer() const { ssize_t offset; sp heap = getMemory(&offset); void* const base = heap!=nullptr ? heap->base() : MAP_FAILED; @@ -158,6 +158,8 @@ void* IMemory::pointer() const { return static_cast(base) + offset; } +void* IMemory::pointer() const { return unsecurePointer(); } + size_t IMemory::size() const { size_t size; getMemory(nullptr, &size); diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h index 071946f50c..8791741f48 100644 --- a/libs/binder/include/binder/IMemory.h +++ b/libs/binder/include/binder/IMemory.h @@ -77,10 +77,33 @@ public: virtual sp getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0; // helpers - void* fastPointer(const sp& heap, ssize_t offset) const; - void* pointer() const; + + // Accessing the underlying pointer must be done with caution, as there are + // some inherent security risks associated with it. When receiving an + // IMemory from an untrusted process, there is currently no way to guarantee + // that this process would't change the content after the fact. This may + // lead to TOC/TOU class of security bugs. In most cases, when performance + // is not an issue, the recommended practice is to immediately copy the + // buffer upon reception, then work with the copy, e.g.: + // + // std::string private_copy(mem.size(), '\0'); + // memcpy(private_copy.data(), mem.unsecurePointer(), mem.size()); + // + // In cases where performance is an issue, this matter must be addressed on + // an ad-hoc basis. + void* unsecurePointer() const; + size_t size() const; ssize_t offset() const; + +private: + // These are now deprecated and are left here for backward-compatibility + // with prebuilts that may reference these symbol at runtime. + // Instead, new code should use unsecurePointer()/unsecureFastPointer(), + // which do the same thing, but make it more obvious that there are some + // security-related pitfalls associated with them. + void* pointer() const; + void* fastPointer(const sp& heap, ssize_t offset) const; }; class BnMemory : public BnInterface -- cgit v1.2.3-59-g8ed1b From 3d8df0e9c84d313bfe2ed7f88dccb984c041bac1 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 17 Sep 2019 14:53:07 +0100 Subject: Crash if too many open files If there are too many open files, and we can't dup a socket because we received EMFILE or ENFILE, let's crash immediately to make this problem obvious. Otherwise, we are simply propagating null pointers through the system and witness null pointer dereference later (in the good cases), or undefined behaviour. Bug: 141111452 Test: none Change-Id: I012bc050e5246456e00c22f0c17a5752b2708875 --- libs/input/InputTransport.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'libs') diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 7835651f11..8a2fc2a2d0 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -362,6 +362,13 @@ sp InputChannel::dup() const { if (!newFd.ok()) { ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), mName.c_str(), strerror(errno)); + const bool hitFdLimit = errno == EMFILE || errno == ENFILE; + // If this process is out of file descriptors, then throwing that might end up exploding + // on the other side of a binder call, which isn't really helpful. + // Better to just crash here and hope that the FD leak is slow. + // Other failures could be client errors, so we still propagate those back to the caller. + LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s", + getName().c_str()); return nullptr; } return InputChannel::create(mName, std::move(newFd)); -- cgit v1.2.3-59-g8ed1b From e0b4d825be2551b94c3f3ea8510cff70ca7fc982 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 11 Sep 2019 18:09:28 -0700 Subject: libtimeinstate: correctly handle devices with no boost freqs initGlobals() should only fail if a cpufreq policy doesn't report any frequencies at all; if scaling_available_frequencies reports some freqs then it's fine if scaling_boost_frequencies is absent Bug: 138317993 Test: libtimeinstate_test passes on a device with no boost freqs Change-Id: I3fe0f2fbdf61888406a687ba4016f9bf7fe4796a Signed-off-by: Connor O'Brien --- libs/cputimeinstate/cputimeinstate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index f255512704..0e12e84324 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -110,9 +110,10 @@ static bool initGlobals() { std::string path = StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name); auto nums = readNumbersFromFile(path); - if (!nums) return false; + if (!nums) continue; freqs.insert(freqs.end(), nums->begin(), nums->end()); } + if (freqs.empty()) return false; std::sort(freqs.begin(), freqs.end()); gPolicyFreqs.emplace_back(freqs); -- cgit v1.2.3-59-g8ed1b From 9dab9730c009b8f45b671c48c7c3fa0915298803 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Tue, 20 Aug 2019 09:29:25 -0700 Subject: Only send surfaces to Listener that registered or applied transaction We must not leak surface controls to processes that shouldn't know about them. With this change, we limit the listeners that receive a callback for a surface control to those that 1) registered the surface control for callback or 2) received and merged a transaction containing that surface control to apply Bug: 139439952 Test: build, boot, IPC_test, SurfaceFlinger_test, libsurfaceflinger_unittest Change-Id: I4eccc3e72d60729c2f3aa7788db0c5c39fbf46b7 --- libs/gui/ISurfaceComposer.cpp | 9 +- libs/gui/LayerState.cpp | 27 +- libs/gui/SurfaceComposerClient.cpp | 81 ++++- libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/LayerState.h | 5 +- libs/gui/include/gui/SurfaceComposerClient.h | 1 + libs/gui/tests/Surface_test.cpp | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 87 ++--- services/surfaceflinger/SurfaceFlinger.h | 27 +- .../surfaceflinger/TransactionCompletedThread.cpp | 22 +- services/surfaceflinger/tests/Android.bp | 41 +++ services/surfaceflinger/tests/IPC_test.cpp | 351 +++++++++++++++++++++ 12 files changed, 566 insertions(+), 88 deletions(-) create mode 100644 services/surfaceflinger/tests/IPC_test.cpp (limited to 'libs') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index dc161b7222..580579759f 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -69,7 +69,7 @@ public: const sp& applyToken, const InputWindowCommands& commands, int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector& listenerCallbacks) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -90,6 +90,7 @@ public: data.writeInt64(desiredPresentTime); data.writeStrongBinder(uncacheBuffer.token.promote()); data.writeUint64(uncacheBuffer.id); + data.writeBool(hasListenerCallbacks); if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) { for (const auto& [listener, callbackIds] : listenerCallbacks) { @@ -1039,6 +1040,8 @@ status_t BnSurfaceComposer::onTransact( uncachedBuffer.token = data.readStrongBinder(); uncachedBuffer.id = data.readUint64(); + bool hasListenerCallbacks = data.readBool(); + std::vector listenerCallbacks; int32_t listenersSize = data.readInt32(); for (int32_t i = 0; i < listenersSize; i++) { @@ -1047,9 +1050,9 @@ status_t BnSurfaceComposer::onTransact( data.readInt64Vector(&callbackIds); listenerCallbacks.emplace_back(listener, callbackIds); } - setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands, - desiredPresentTime, uncachedBuffer, listenerCallbacks); + desiredPresentTime, uncachedBuffer, hasListenerCallbacks, + listenerCallbacks); return NO_ERROR; } case BOOT_FINISHED: { diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 523ed1d2ce..e004e9584c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -86,7 +86,6 @@ status_t layer_state_t::write(Parcel& output) const memcpy(output.writeInplace(16 * sizeof(float)), colorTransform.asArray(), 16 * sizeof(float)); output.writeFloat(cornerRadius); - output.writeBool(hasListenerCallbacks); output.writeStrongBinder(cachedBuffer.token.promote()); output.writeUint64(cachedBuffer.id); output.writeParcelable(metadata); @@ -95,6 +94,22 @@ status_t layer_state_t::write(Parcel& output) const output.writeUint32(static_cast(bgColorDataspace)); output.writeBool(colorSpaceAgnostic); + auto err = output.writeVectorSize(listeners); + if (err) { + return err; + } + + for (auto listener : listeners) { + err = output.writeStrongBinder(listener.transactionCompletedListener); + if (err) { + return err; + } + err = output.writeInt64Vector(listener.callbackIds); + if (err) { + return err; + } + } + return NO_ERROR; } @@ -156,7 +171,6 @@ status_t layer_state_t::read(const Parcel& input) colorTransform = mat4(static_cast(input.readInplace(16 * sizeof(float)))); cornerRadius = input.readFloat(); - hasListenerCallbacks = input.readBool(); cachedBuffer.token = input.readStrongBinder(); cachedBuffer.id = input.readUint64(); input.readParcelable(&metadata); @@ -165,6 +179,14 @@ status_t layer_state_t::read(const Parcel& input) bgColorDataspace = static_cast(input.readUint32()); colorSpaceAgnostic = input.readBool(); + int32_t numListeners = input.readInt32(); + listeners.clear(); + for (int i = 0; i < numListeners; i++) { + auto listener = input.readStrongBinder(); + std::vector callbackIds; + input.readInt64Vector(&callbackIds); + listeners.emplace_back(listener, callbackIds); + } return NO_ERROR; } @@ -361,7 +383,6 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eHasListenerCallbacksChanged) { what |= eHasListenerCallbacksChanged; - hasListenerCallbacks = other.hasListenerCallbacks; } #ifndef NO_INPUT diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 67dd726eba..6b5021d1b4 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -362,6 +362,33 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel displayStates.add(displayState); } + count = static_cast(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::unordered_map, CallbackInfo, TCLHash> listenerCallbacks; + listenerCallbacks.reserve(count); + for (size_t i = 0; i < count; i++) { + sp listener = + interface_cast(parcel->readStrongBinder()); + size_t numCallbackIds = parcel->readUint32(); + if (numCallbackIds > parcel->dataSize()) { + return BAD_VALUE; + } + for (size_t j = 0; j < numCallbackIds; j++) { + listenerCallbacks[listener].callbackIds.insert(parcel->readInt64()); + } + size_t numSurfaces = parcel->readUint32(); + if (numSurfaces > parcel->dataSize()) { + return BAD_VALUE; + } + for (size_t j = 0; j < numSurfaces; j++) { + sp surface; + surface = SurfaceControl::readFromParcel(parcel); + listenerCallbacks[listener].surfaceControls.insert(surface); + } + } + count = static_cast(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; @@ -389,10 +416,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mDisplayStates = displayStates; + mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; mInputWindowCommands = inputWindowCommands; - // listener callbacks contain function pointer addresses and may not be safe to parcel. - mListenerCallbacks.clear(); return NO_ERROR; } @@ -408,6 +434,19 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const displayState.write(*parcel); } + parcel->writeUint32(static_cast(mListenerCallbacks.size())); + for (auto const& [listener, callbackInfo] : mListenerCallbacks) { + parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener)); + parcel->writeUint32(static_cast(callbackInfo.callbackIds.size())); + for (auto callbackId : callbackInfo.callbackIds) { + parcel->writeInt64(callbackId); + } + parcel->writeUint32(static_cast(callbackInfo.surfaceControls.size())); + for (auto surfaceControl : callbackInfo.surfaceControls) { + surfaceControl->writeToParcel(parcel); + } + } + parcel->writeUint32(static_cast(mComposerStates.size())); for (auto const& [surfaceHandle, composerState] : mComposerStates) { parcel->writeStrongBinder(surfaceHandle); @@ -441,6 +480,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator( callbackIds.begin()), std::make_move_iterator(callbackIds.end())); + // register surface controls for this listener that is merging + for (const auto& surfaceControl : surfaceControls) { + registerSurfaceControlForCallback(surfaceControl); + } + mListenerCallbacks[listener] .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()), std::make_move_iterator(surfaceControls.end())); @@ -479,7 +523,7 @@ void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle composerStates.add(s); sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, {}); + sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, false, {}); } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { @@ -490,7 +534,7 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { uncacheBuffer.id = cacheId; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, {}); + sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, false, {}); } void SurfaceComposerClient::Transaction::cacheBuffers() { @@ -539,8 +583,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { sp sf(ComposerService::getComposerService()); + bool hasListenerCallbacks = !mListenerCallbacks.empty(); std::vector listenerCallbacks; - // For every listener with registered callbacks for (const auto& [listener, callbackInfo] : mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; @@ -548,19 +592,24 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { continue; } - listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds)); - - // If the listener has any SurfaceControls set on this Transaction update the surface state - for (const auto& surfaceControl : surfaceControls) { - layer_state_t* s = getLayerState(surfaceControl); - if (!s) { - ALOGE("failed to get layer state"); - continue; + if (surfaceControls.empty()) { + listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds)); + } else { + // If the listener has any SurfaceControls set on this Transaction update the surface + // state + for (const auto& surfaceControl : surfaceControls) { + layer_state_t* s = getLayerState(surfaceControl); + if (!s) { + ALOGE("failed to get layer state"); + continue; + } + std::vector callbacks(callbackIds.begin(), callbackIds.end()); + s->what |= layer_state_t::eHasListenerCallbacksChanged; + s->listeners.emplace_back(IInterface::asBinder(listener), callbacks); } - s->what |= layer_state_t::eHasListenerCallbacksChanged; - s->hasListenerCallbacks = true; } } + mListenerCallbacks.clear(); cacheBuffers(); @@ -598,7 +647,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, - listenerCallbacks); + hasListenerCallbacks, listenerCallbacks); mInputWindowCommands.clear(); mStatus = NO_ERROR; return NO_ERROR; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index c84910b6ec..06be1b36b2 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -140,7 +140,7 @@ public: const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector& listenerCallbacks) = 0; /* signal that we're done booting. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 2eb5492558..a49ed525b6 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -23,6 +23,7 @@ #include #include +#include #include #ifndef NO_INPUT @@ -123,7 +124,6 @@ struct layer_state_t { surfaceDamageRegion(), api(-1), colorTransform(mat4()), - hasListenerCallbacks(false), bgColorAlpha(0), bgColorDataspace(ui::Dataspace::UNKNOWN), colorSpaceAgnostic(false) { @@ -186,7 +186,6 @@ struct layer_state_t { sp sidebandStream; mat4 colorTransform; - bool hasListenerCallbacks; #ifndef NO_INPUT InputWindowInfo inputInfo; #endif @@ -203,6 +202,8 @@ struct layer_state_t { // A color space agnostic layer means the color of this layer can be // interpreted in any color space. bool colorSpaceAgnostic; + + std::vector listeners; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 8a6920c268..15287e2cb6 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -291,6 +291,7 @@ public: }; class Transaction : public Parcelable { + protected: std::unordered_map, ComposerState, IBinderHash> mComposerStates; SortedVector mDisplayStates; std::unordered_map, CallbackInfo, TCLHash> diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 5a121d77ab..d75b1cace5 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -688,6 +688,7 @@ public: const sp& /*applyToken*/, const InputWindowCommands& /*inputWindowCommands*/, int64_t /*desiredPresentTime*/, const client_cache_t& /*cachedBuffer*/, + bool /*hasListenerCallbacks*/, const std::vector& /*listenerCallbacks*/) override { } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 02690b0b6a..6576be2984 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3100,9 +3100,9 @@ bool SurfaceFlinger::flushTransactionQueues() { transactions.push_back(transaction); applyTransactionState(transaction.states, transaction.displays, transaction.flags, mPendingInputWindowCommands, transaction.desiredPresentTime, - transaction.buffer, transaction.callback, - transaction.postTime, transaction.privileged, - /*isMainThread*/ true); + transaction.buffer, transaction.postTime, + transaction.privileged, transaction.hasListenerCallbacks, + transaction.listenerCallbacks, /*isMainThread*/ true); transactionQueue.pop(); flushedATransaction = true; } @@ -3149,13 +3149,11 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, return true; } -void SurfaceFlinger::setTransactionState(const Vector& states, - const Vector& displays, uint32_t flags, - const sp& applyToken, - const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, - const std::vector& listenerCallbacks) { +void SurfaceFlinger::setTransactionState( + const Vector& states, const Vector& displays, uint32_t flags, + const sp& applyToken, const InputWindowCommands& inputWindowCommands, + int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + const std::vector& listenerCallbacks) { ATRACE_CALL(); const int64_t postTime = systemTime(); @@ -3185,24 +3183,23 @@ void SurfaceFlinger::setTransactionState(const Vector& states, if (itr != mTransactionQueues.end() || !transactionIsReadyToBeApplied( desiredPresentTime, false /* useCachedExpectedPresentTime */, states)) { mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime, - uncacheBuffer, listenerCallbacks, postTime, - privileged); + uncacheBuffer, postTime, privileged, + hasListenerCallbacks, listenerCallbacks); setTransactionFlags(eTransactionFlushNeeded); return; } applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime, - uncacheBuffer, listenerCallbacks, postTime, privileged); + uncacheBuffer, postTime, privileged, hasListenerCallbacks, + listenerCallbacks); } -void SurfaceFlinger::applyTransactionState(const Vector& states, - const Vector& displays, uint32_t flags, - const InputWindowCommands& inputWindowCommands, - const int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, - const std::vector& listenerCallbacks, - const int64_t postTime, bool privileged, - bool isMainThread) { +void SurfaceFlinger::applyTransactionState( + const Vector& states, const Vector& displays, uint32_t flags, + const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, + const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged, + bool hasListenerCallbacks, const std::vector& listenerCallbacks, + bool isMainThread) { uint32_t transactionFlags = 0; if (flags & eAnimation) { @@ -3225,28 +3222,27 @@ void SurfaceFlinger::applyTransactionState(const Vector& states, transactionFlags |= setDisplayStateLocked(display); } - // In case the client has sent a Transaction that should receive callbacks but without any - // SurfaceControls that should be included in the callback, send the listener and callbackIds - // to the callback thread so it can send an empty callback - if (!listenerCallbacks.empty()) { - mTransactionCompletedThread.run(); - } - for (const auto& listenerCallback : listenerCallbacks) { - mTransactionCompletedThread.startRegistration(listenerCallback); + // start and end registration for listeners w/ no surface so they can get their callback. Note + // that listeners with SurfaceControls will start registration during setClientStateLocked + // below. + for (const auto& listener : listenerCallbacks) { + mTransactionCompletedThread.startRegistration(listener); + mTransactionCompletedThread.endRegistration(listener); } + std::unordered_set listenerCallbacksWithSurfaces; uint32_t clientStateFlags = 0; for (const ComposerState& state : states) { - clientStateFlags |= setClientStateLocked(state, desiredPresentTime, listenerCallbacks, - postTime, privileged); + clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged, + listenerCallbacksWithSurfaces); } - for (const auto& listenerCallback : listenerCallbacks) { + for (const auto& listenerCallback : listenerCallbacksWithSurfaces) { mTransactionCompletedThread.endRegistration(listenerCallback); } // If the state doesn't require a traversal and there are callbacks, send them now - if (!(clientStateFlags & eTraversalNeeded) && !listenerCallbacks.empty()) { + if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) { mTransactionCompletedThread.sendCallbacks(); } transactionFlags |= clientStateFlags; @@ -3374,17 +3370,23 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess() { } uint32_t SurfaceFlinger::setClientStateLocked( - const ComposerState& composerState, int64_t desiredPresentTime, - const std::vector& listenerCallbacks, int64_t postTime, - bool privileged) { + const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime, + bool privileged, + std::unordered_set& listenerCallbacks) { const layer_state_t& s = composerState.state; + for (auto& listener : s.listeners) { + // note that startRegistration will not re-register if the listener has + // already be registered for a prior surface control + mTransactionCompletedThread.startRegistration(listener); + listenerCallbacks.insert(listener); + } + sp layer(fromHandle(s.surface)); if (layer == nullptr) { - for (auto& listenerCallback : listenerCallbacks) { + for (auto& [listener, callbackIds] : s.listeners) { mTransactionCompletedThread.registerUnpresentedCallbackHandle( - new CallbackHandle(listenerCallback.transactionCompletedListener, - listenerCallback.callbackIds, s.surface)); + new CallbackHandle(listener, callbackIds, s.surface)); } return 0; } @@ -3607,8 +3609,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } std::vector> callbackHandles; - if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) { - for (const auto& [listener, callbackIds] : listenerCallbacks) { + if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!s.listeners.empty())) { + for (auto& [listener, callbackIds] : s.listeners) { callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); } } @@ -3890,7 +3892,8 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, {}); + setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false, + {}); setPowerModeInternal(display, HWC_POWER_MODE_NORMAL); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f220c26bdf..3467de2a51 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -400,6 +400,7 @@ private: const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, + bool hasListenerCallbacks, const std::vector& listenerCallbacks) override; void bootFinished() override; bool authenticateSurfaceTexture( @@ -568,10 +569,10 @@ private: const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, - const client_cache_t& uncacheBuffer, + const client_cache_t& uncacheBuffer, const int64_t postTime, + bool privileged, bool hasListenerCallbacks, const std::vector& listenerCallbacks, - const int64_t postTime, bool privileged, bool isMainThread = false) - REQUIRES(mStateLock); + bool isMainThread = false) REQUIRES(mStateLock); // Returns true if at least one transaction was flushed bool flushTransactionQueues(); // Returns true if there is at least one transaction that needs to be flushed @@ -586,9 +587,11 @@ private: bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, bool useCachedExpectedPresentTime, const Vector& states); - uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime, - const std::vector& listenerCallbacks, - int64_t postTime, bool privileged) REQUIRES(mStateLock); + uint32_t setClientStateLocked( + const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime, + bool privileged, + std::unordered_set& listenerCallbacks) + REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); @@ -1024,25 +1027,27 @@ private: TransactionState(const Vector& composerStates, const Vector& displayStates, uint32_t transactionFlags, int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, - const std::vector& listenerCallbacks, int64_t postTime, - bool privileged) + int64_t postTime, bool privileged, bool hasListenerCallbacks, + std::vector listenerCallbacks) : states(composerStates), displays(displayStates), flags(transactionFlags), desiredPresentTime(desiredPresentTime), buffer(uncacheBuffer), - callback(listenerCallbacks), postTime(postTime), - privileged(privileged) {} + privileged(privileged), + hasListenerCallbacks(hasListenerCallbacks), + listenerCallbacks(listenerCallbacks) {} Vector states; Vector displays; uint32_t flags; const int64_t desiredPresentTime; client_cache_t buffer; - std::vector callback; const int64_t postTime; bool privileged; + bool hasListenerCallbacks; + std::vector listenerCallbacks; }; std::unordered_map, std::queue, IListenerHash> mTransactionQueues; diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp index 1324f20e1c..92e59d7745 100644 --- a/services/surfaceflinger/TransactionCompletedThread.cpp +++ b/services/surfaceflinger/TransactionCompletedThread.cpp @@ -75,27 +75,29 @@ void TransactionCompletedThread::run() { } status_t TransactionCompletedThread::startRegistration(const ListenerCallbacks& listenerCallbacks) { + // begin running if not already running + run(); std::lock_guard lock(mMutex); if (!mRunning) { ALOGE("cannot add callback because the callback thread isn't running"); return BAD_VALUE; } + auto [itr, inserted] = mRegisteringTransactions.insert(listenerCallbacks); auto& [listener, callbackIds] = listenerCallbacks; - if (mCompletedTransactions.count(listener) == 0) { - status_t err = listener->linkToDeath(mDeathRecipient); - if (err != NO_ERROR) { - ALOGE("cannot add callback because linkToDeath failed, err: %d", err); - return err; + if (inserted) { + if (mCompletedTransactions.count(listener) == 0) { + status_t err = listener->linkToDeath(mDeathRecipient); + if (err != NO_ERROR) { + ALOGE("cannot add callback because linkToDeath failed, err: %d", err); + return err; + } } + auto& transactionStatsDeque = mCompletedTransactions[listener]; + transactionStatsDeque.emplace_back(callbackIds); } - mRegisteringTransactions.insert(listenerCallbacks); - - auto& transactionStatsDeque = mCompletedTransactions[listener]; - transactionStatsDeque.emplace_back(callbackIds); - return NO_ERROR; } diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 159c2a464a..7f960f302a 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -43,7 +43,48 @@ cc_test { "libui", "libutils", ] +} + +cc_defaults { + name: "ipc_defaults", + cflags: [ + "-Wall", + "-Werror", + ], +} +cc_test { + name: "IPC_test", + defaults: ["ipc_defaults"], + test_suites: ["device-tests"], + srcs: [ + "BufferGenerator.cpp", + "IPC_test.cpp", + ], + cppflags: [ + "-Wall", + "-Werror", + "-Wformat", + "-Wthread-safety", + "-Wunused", + "-Wunreachable-code", + ], + shared_libs: [ + "libandroid", + "libbinder", + "libcutils", + "libEGL", + "libGLESv2", + "libgui", + "liblayers_proto", + "liblog", + "libprotobuf-cpp-full", + "libtimestats_proto", + "libui", + "libutils", + ], + cpp_std: "experimental", + gnu_extensions: false, } subdirs = [ diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp new file mode 100644 index 0000000000..8a756a668c --- /dev/null +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2019 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 + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +#include "BufferGenerator.h" +#include "utils/CallbackUtils.h" +#include "utils/ColorUtils.h" +#include "utils/TransactionUtils.h" + +namespace android { + +namespace test { + +using Transaction = SurfaceComposerClient::Transaction; +using CallbackInfo = SurfaceComposerClient::CallbackInfo; +using TCLHash = SurfaceComposerClient::TCLHash; +using android::hardware::graphics::common::V1_1::BufferUsage; + +class TransactionHelper : public Transaction { +public: + size_t getNumListeners() { return mListenerCallbacks.size(); } + + std::unordered_map, CallbackInfo, TCLHash> + getListenerCallbacks() { + return mListenerCallbacks; + } +}; + +class IPCTestUtils { +public: + static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult, + bool finalState = false); + static status_t getBuffer(sp* outBuffer, sp* outFence); +}; + +class IIPCTest : public IInterface { +public: + DECLARE_META_INTERFACE(IPCTest) + enum class Tag : uint32_t { + SetDeathToken = IBinder::FIRST_CALL_TRANSACTION, + InitClient, + CreateTransaction, + MergeAndApply, + VerifyCallbacks, + CleanUp, + Last, + }; + + virtual status_t setDeathToken(sp& token) = 0; + + virtual status_t initClient() = 0; + + virtual status_t createTransaction(TransactionHelper* outTransaction, uint32_t width, + uint32_t height) = 0; + + virtual status_t mergeAndApply(TransactionHelper transaction) = 0; + + virtual status_t verifyCallbacks() = 0; + + virtual status_t cleanUp() = 0; +}; + +class BpIPCTest : public SafeBpInterface { +public: + explicit BpIPCTest(const sp& impl) : SafeBpInterface(impl, "BpIPCTest") {} + + status_t setDeathToken(sp& token) { + return callRemote(Tag::SetDeathToken, token); + } + + status_t initClient() { return callRemote(Tag::InitClient); } + + status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) { + return callRemote(Tag::CreateTransaction, + transaction, width, height); + } + + status_t mergeAndApply(TransactionHelper transaction) { + return callRemote(Tag::MergeAndApply, transaction); + } + + status_t verifyCallbacks() { + return callRemote(Tag::VerifyCallbacks); + } + + status_t cleanUp() { return callRemote(Tag::CleanUp); } +}; + +IMPLEMENT_META_INTERFACE(IPCTest, "android.gfx.tests.IIPCTest") + +class onTestDeath : public IBinder::DeathRecipient { +public: + void binderDied(const wp& /*who*/) override { + ALOGE("onTestDeath::binderDied, exiting"); + exit(0); + } +}; + +sp getDeathToken() { + static sp token = new onTestDeath; + return token; +} + +class BnIPCTest : public SafeBnInterface { +public: + BnIPCTest() : SafeBnInterface("BnIPCTest") {} + + status_t setDeathToken(sp& token) override { + return token->linkToDeath(getDeathToken()); + } + + status_t initClient() override { + mClient = new SurfaceComposerClient; + auto err = mClient->initCheck(); + return err; + } + + status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) { + if (transaction == nullptr) { + ALOGE("Error in createTransaction: transaction is nullptr"); + return BAD_VALUE; + } + mSurfaceControl = mClient->createSurface(String8("parentProcessSurface"), 0, 0, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + /*parent*/ nullptr); + sp gb; + sp fence; + int err = IPCTestUtils::getBuffer(&gb, &fence); + if (err != NO_ERROR) return err; + + TransactionUtils::fillGraphicBufferColor(gb, + {0, 0, static_cast(width), + static_cast(height)}, + Color::RED); + transaction->setLayerStack(mSurfaceControl, 0) + .setLayer(mSurfaceControl, std::numeric_limits::max()) + .setFrame(mSurfaceControl, Rect(0, 0, width, height)) + .setBuffer(mSurfaceControl, gb) + .setAcquireFence(mSurfaceControl, fence) + .show(mSurfaceControl) + .addTransactionCompletedCallback(mCallbackHelper.function, + mCallbackHelper.getContext()); + return NO_ERROR; + } + + status_t mergeAndApply(TransactionHelper /*transaction*/) { + // transaction.apply(); + return NO_ERROR; + } + + status_t verifyCallbacks() { + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, mSurfaceControl); + EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(mCallbackHelper, expected, true)); + return NO_ERROR; + } + + status_t cleanUp() { + if (mClient) mClient->dispose(); + mSurfaceControl = nullptr; + IPCThreadState::self()->stopProcess(); + return NO_ERROR; + } + + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t /*flags*/) override { + EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION); + EXPECT_LT(code, static_cast(IIPCTest::Tag::Last)); + switch (static_cast(code)) { + case IIPCTest::Tag::SetDeathToken: + return callLocal(data, reply, &IIPCTest::setDeathToken); + case IIPCTest::Tag::InitClient: + return callLocal(data, reply, &IIPCTest::initClient); + case IIPCTest::Tag::CreateTransaction: + return callLocal(data, reply, &IIPCTest::createTransaction); + case IIPCTest::Tag::MergeAndApply: + return callLocal(data, reply, &IIPCTest::mergeAndApply); + case IIPCTest::Tag::VerifyCallbacks: + return callLocal(data, reply, &IIPCTest::verifyCallbacks); + case IIPCTest::Tag::CleanUp: + return callLocal(data, reply, &IIPCTest::cleanUp); + default: + return UNKNOWN_ERROR; + } + } + +private: + sp mClient; + sp mSurfaceControl; + CallbackHelper mCallbackHelper; +}; + +class IPCTest : public ::testing::Test { +public: + IPCTest() : mDeathRecipient(new BBinder), mRemote(initRemoteService()) { + ProcessState::self()->startThreadPool(); + } + void SetUp() { + mClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mClient->initCheck()); + + mPrimaryDisplay = mClient->getInternalDisplayToken(); + DisplayInfo info; + mClient->getDisplayInfo(mPrimaryDisplay, &info); + mDisplayWidth = info.w; + mDisplayHeight = info.h; + + Transaction setupTransaction; + setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0); + setupTransaction.apply(); + } + +protected: + sp initRemoteService(); + + sp mDeathRecipient; + sp mRemote; + sp mClient; + sp mPrimaryDisplay; + uint32_t mDisplayWidth; + uint32_t mDisplayHeight; + sp sc; +}; + +status_t IPCTestUtils::getBuffer(sp* outBuffer, sp* outFence) { + static BufferGenerator bufferGenerator; + return bufferGenerator.get(outBuffer, outFence); +} + +void IPCTestUtils::waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult, + bool finalState) { + CallbackData callbackData; + ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData)); + EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData)); + + if (finalState) { + ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState()); + } +} + +sp IPCTest::initRemoteService() { + static std::mutex mMutex; + static sp remote; + const String16 serviceName("IPCTest"); + + std::unique_lock lock; + if (remote == nullptr) { + pid_t forkPid = fork(); + EXPECT_NE(forkPid, -1); + + if (forkPid == 0) { + sp nativeService = new BnIPCTest; + if (!nativeService) { + ALOGE("null service..."); + } + status_t err = defaultServiceManager()->addService(serviceName, + IInterface::asBinder(nativeService)); + if (err != NO_ERROR) { + ALOGE("failed to add service: %d", err); + } + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + [&]() { exit(0); }(); + } + sp binder = defaultServiceManager()->getService(serviceName); + remote = interface_cast(binder); + remote->setDeathToken(mDeathRecipient); + } + return remote; +} + +TEST_F(IPCTest, MergeBasic) { + CallbackHelper helper1; + sc = mClient->createSurface(String8("parentProcessSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + /*parent*/ nullptr); + sp gb; + sp fence; + int err = IPCTestUtils::getBuffer(&gb, &fence); + ASSERT_EQ(NO_ERROR, err); + TransactionUtils::fillGraphicBufferColor(gb, + {0, 0, static_cast(mDisplayWidth), + static_cast(mDisplayHeight)}, + Color::RED); + + Transaction transaction; + transaction.setLayerStack(sc, 0) + .setLayer(sc, std::numeric_limits::max() - 1) + .setBuffer(sc, gb) + .setAcquireFence(sc, fence) + .show(sc) + .addTransactionCompletedCallback(helper1.function, helper1.getContext()); + + TransactionHelper remote; + mRemote->initClient(); + mRemote->createTransaction(&remote, mDisplayWidth / 2, mDisplayHeight / 2); + ASSERT_EQ(1, remote.getNumListeners()); + auto remoteListenerCallbacks = remote.getListenerCallbacks(); + auto remoteCallback = remoteListenerCallbacks.begin(); + auto remoteCallbackInfo = remoteCallback->second; + auto remoteListenerScs = remoteCallbackInfo.surfaceControls; + ASSERT_EQ(1, remoteCallbackInfo.callbackIds.size()); + ASSERT_EQ(1, remoteListenerScs.size()); + + sp remoteSc = *(remoteListenerScs.begin()); + transaction.merge(std::move(remote)); + transaction.apply(); + + sleep(1); + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, sc); + expected.addSurface(ExpectedResult::Transaction::PRESENTED, remoteSc); + EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(helper1, expected, true)); + + mRemote->verifyCallbacks(); + mRemote->cleanUp(); +} + +} // namespace test +} // namespace android -- cgit v1.2.3-59-g8ed1b From e409e38f7a874d02c5900f201ba38ca94837aea6 Mon Sep 17 00:00:00 2001 From: williamtai Date: Mon, 9 Sep 2019 10:08:22 +0800 Subject: libgui: Set HDR metadataSize data type as uint32_t sizeof(metadataSize) is different in 32-bit or 64-bit mode if data type of metadataSize is size_t. Fix metadataSize in uint32_t for flatten and unflatten. In addition, we take hdr10plus array element size into consideration when allocate memoery for flatten and unflatten. b/127370432 Test: check size of metadataSize in flatten and unflatten in hdr10plus playback. Test: Check hdr10plus array content when array element size is non-uint8_t such as uint32_t. Change-Id: Id7a415887b43c440e3f23ea2f6b201d45271c160 --- libs/gui/HdrMetadata.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'libs') diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp index add3ef0458..058cd9aa3b 100644 --- a/libs/gui/HdrMetadata.cpp +++ b/libs/gui/HdrMetadata.cpp @@ -28,8 +28,8 @@ size_t HdrMetadata::getFlattenedSize() const { size += sizeof(cta8613); } if (validTypes & HDR10PLUS) { - size += sizeof(size_t); - size += hdr10plus.size(); + size += sizeof(uint32_t); + size += hdr10plus.size() * sizeof(hdr10plus[0]); } return size; } @@ -47,10 +47,11 @@ status_t HdrMetadata::flatten(void* buffer, size_t size) const { FlattenableUtils::write(buffer, size, cta8613); } if (validTypes & HDR10PLUS) { - size_t metadataSize = hdr10plus.size(); + uint32_t metadataSize = hdr10plus.size(); FlattenableUtils::write(buffer, size, metadataSize); - memcpy(buffer, hdr10plus.data(), metadataSize); - FlattenableUtils::advance(buffer, size, metadataSize); + size_t metadataSizeinByte = metadataSize * sizeof(hdr10plus[0]); + memcpy(buffer, hdr10plus.data(), metadataSizeinByte); + FlattenableUtils::advance(buffer, size, metadataSizeinByte); } return NO_ERROR; @@ -74,20 +75,21 @@ status_t HdrMetadata::unflatten(void const* buffer, size_t size) { FlattenableUtils::read(buffer, size, cta8613); } if (validTypes & HDR10PLUS) { - if (size < sizeof(size_t)) { + if (size < sizeof(uint32_t)) { return NO_MEMORY; } - size_t metadataSize; + uint32_t metadataSize; FlattenableUtils::read(buffer, size, metadataSize); - if (size < metadataSize) { + size_t metadataSizeinByte = metadataSize * sizeof(hdr10plus[0]); + if (size < metadataSizeinByte) { return NO_MEMORY; } hdr10plus.resize(metadataSize); - memcpy(hdr10plus.data(), buffer, metadataSize); - FlattenableUtils::advance(buffer, size, metadataSize); + memcpy(hdr10plus.data(), buffer, metadataSizeinByte); + FlattenableUtils::advance(buffer, size, metadataSizeinByte); } return NO_ERROR; -- cgit v1.2.3-59-g8ed1b From de4bf150c5685643daa1fa17f697e8b1cf3ea9ec Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 16 Aug 2019 11:12:52 -0500 Subject: Do not report latency for injected events When reporting the latency of touch events, ensure that injected events are excluded. These events can have arbitrary timestamps, and would not result in meaningful data. Also do not report events for statistics if inputfilter is enabled. Move the statistics reporting from InputTransport to InputDispatcher. This ensures that there's only 1 instance of the mStatistics object. This also provides easy access to the inputfilterenabled state. Bug: 13894199 Test: Change the reporting period to 0 (to report every event immediately) Inject events in various ways and ensure they don't go to statsd $ m statsd_testdrive && ./out/host/linux-x86/bin/statsd_testdrive 34 $ adb shell input tap 100 100 $ adb shell monkey 1000 Next, relaunch the statsd_testdrive script and touch the screen Observe that events are reported. Change-Id: Ief8040599a347e084e75584ed3164c60a6dbc4ad --- include/input/InputTransport.h | 5 ---- libs/input/Android.bp | 1 - libs/input/InputTransport.cpp | 15 ----------- libs/input/LatencyStatistics.cpp | 2 +- services/inputflinger/Android.bp | 1 + services/inputflinger/dispatcher/Android.bp | 1 + services/inputflinger/dispatcher/Entry.h | 18 +++++++++++++ .../inputflinger/dispatcher/InputDispatcher.cpp | 30 ++++++++++++++++++++++ services/inputflinger/dispatcher/InputDispatcher.h | 5 ++++ services/inputflinger/dispatcher/InputState.h | 3 --- 10 files changed, 56 insertions(+), 25 deletions(-) (limited to 'libs') diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 28b8d80074..c056c972d2 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -35,7 +35,6 @@ #include #include

& crop, hidl_vec* outCrop) { + return encodeMetadata(MetadataType_Crop, crop, outCrop, encodeCropHelper); +} + +status_t decodeCrop(const hidl_vec& crop, std::vector* outCrop) { + return decodeMetadata(MetadataType_Crop, crop, outCrop, decodeCropHelper, clearCrop); +} + status_t encodeDataspace(const Dataspace& dataspace, hidl_vec* outDataspace) { return encodeMetadata(MetadataType_Dataspace, static_cast(dataspace), outDataspace, encodeInteger); diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp index b5644beafb..dc22385883 100644 --- a/libs/gralloc/types/fuzzer/gralloctypes.cpp +++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp @@ -70,6 +70,7 @@ std::vector GRALLOCTYPES_DECODE_FUNCTIONS { GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeInterlaced), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::ExtendableType, ::android::gralloc4::decodeChromaSiting), GRALLOCTYPES_DECODE(std::vector, ::android::gralloc4::decodePlaneLayouts), + GRALLOCTYPES_DECODE(std::vector, ::android::gralloc4::decodeCrop), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::Dataspace, ::android::gralloc4::decodeDataspace), GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::BlendMode, ::android::gralloc4::decodeBlendMode), GRALLOCTYPES_DECODE(std::optional, ::android::gralloc4::decodeSmpte2086), diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index d8554398c3..5ec4d0df3c 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -89,6 +89,24 @@ inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lh return !(lhs == rhs); } +inline bool operator==(const std::vector& lhs, + const std::vector& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + for (size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] != rhs[i]) { + return false; + } + } + return true; +} + +inline bool operator!=(const std::vector& lhs, + const std::vector& rhs) { + return !(lhs == rhs); +} + inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs, const aidl::android::hardware::graphics::common::PlaneLayout& rhs) { if (lhs.offsetInBytes != rhs.offsetInBytes) { @@ -115,9 +133,6 @@ inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLay if (lhs.verticalSubsampling != rhs.verticalSubsampling) { return false; } - if (lhs.crop != rhs.crop) { - return false; - } if (lhs.components.size() != rhs.components.size()) { return false; } @@ -286,6 +301,10 @@ static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType Me GRALLOC4_STANDARD_METADATA_TYPE, static_cast(aidl::android::hardware::graphics::common::StandardMetadataType::PLANE_LAYOUTS) }; +static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Crop = { + GRALLOC4_STANDARD_METADATA_TYPE, static_cast(aidl::android::hardware::graphics::common::StandardMetadataType::CROP) +}; + static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType MetadataType_Dataspace = { GRALLOC4_STANDARD_METADATA_TYPE, static_cast(aidl::android::hardware::graphics::common::StandardMetadataType::DATASPACE) }; @@ -469,6 +488,9 @@ status_t decodeChromaSiting(const android::hardware::hidl_vec& chromaSi status_t encodePlaneLayouts(const std::vector& planeLayouts, android::hardware::hidl_vec* outPlaneLayouts); status_t decodePlaneLayouts(const android::hardware::hidl_vec& planeLayouts, std::vector* outPlaneLayouts); +status_t encodeCrop(const std::vector& crop, android::hardware::hidl_vec* outCrop); +status_t decodeCrop(const android::hardware::hidl_vec& crop, std::vector* outCrop); + status_t encodeDataspace(const aidl::android::hardware::graphics::common::Dataspace& dataspace, android::hardware::hidl_vec* outDataspace); status_t decodeDataspace(const android::hardware::hidl_vec& dataspace, aidl::android::hardware::graphics::common::Dataspace* outDataspace); diff --git a/libs/gralloc/types/tests/Gralloc4_test.cpp b/libs/gralloc/types/tests/Gralloc4_test.cpp index dbe41f16cc..89cbf4ac4a 100644 --- a/libs/gralloc/types/tests/Gralloc4_test.cpp +++ b/libs/gralloc/types/tests/Gralloc4_test.cpp @@ -321,10 +321,6 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { planeLayoutA.totalSizeInBytes = planeLayoutA.strideInBytes * height; planeLayoutA.horizontalSubsampling = 1; planeLayoutA.verticalSubsampling = 1; - planeLayoutA.crop.left = 0; - planeLayoutA.crop.top = 0; - planeLayoutA.crop.right = width; - planeLayoutA.crop.bottom = height; component.type = gralloc4::PlaneLayoutComponentType_A; component.offsetInBits = 0; @@ -341,11 +337,6 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { planeLayoutRGB.totalSizeInBytes = planeLayoutRGB.strideInBytes * height; planeLayoutRGB.horizontalSubsampling = 1; planeLayoutRGB.verticalSubsampling = 1; - planeLayoutRGB.crop.left = 0; - planeLayoutRGB.crop.top = 0; - planeLayoutRGB.crop.right = width; - planeLayoutRGB.crop.bottom = height; - component.type = gralloc4::PlaneLayoutComponentType_R; planeLayoutRGB.components.push_back(component); component.type = gralloc4::PlaneLayoutComponentType_G; @@ -358,6 +349,33 @@ TEST_F(Gralloc4TestPlaneLayouts, PlaneLayouts) { ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(planeLayouts, gralloc4::encodePlaneLayouts, gralloc4::decodePlaneLayouts)); } +class Gralloc4TestCrop : public testing::Test { }; + +TEST_F(Gralloc4TestCrop, Crop) { + std::vector crops; + Rect crop1, crop2, crop3; + + crop1.left = 0; + crop1.top = 0; + crop1.right = 64; + crop1.bottom = 64; + crops.push_back(crop1); + + crop2.left = std::numeric_limits::min(); + crop2.top = 0xFF; + crop2.right = std::numeric_limits::max(); + crop2.bottom = 0xFFFF; + crops.push_back(crop2); + + crop3.left = 0; + crop3.top = 0; + crop3.right = -1; + crop3.bottom = -1; + crops.push_back(crop3); + + ASSERT_NO_FATAL_FAILURE(testHelperStableAidlType(crops, gralloc4::encodeCrop, gralloc4::decodeCrop)); +} + class Gralloc4TestDataspace : public testing::TestWithParam { }; INSTANTIATE_TEST_CASE_P( -- cgit v1.2.3-59-g8ed1b From 786eda95575878f8bf6d79772cbc69211e45facb Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 10 Feb 2020 12:27:07 -0800 Subject: rm libbinderthreadstate Empty, since the functionality was moved to libbinder/libhwbinder to remove extra lib dependency. Bug: 148692216 Test: N/A Change-Id: Ic314bbe5e05b009960038f4ef970306ba970f81a --- libs/binder/fuzzer/Android.bp | 1 - 1 file changed, 1 deletion(-) (limited to 'libs') diff --git a/libs/binder/fuzzer/Android.bp b/libs/binder/fuzzer/Android.bp index 521d36fced..d2b4d52acc 100644 --- a/libs/binder/fuzzer/Android.bp +++ b/libs/binder/fuzzer/Android.bp @@ -16,7 +16,6 @@ cc_fuzz { ], static_libs: [ "libbase", - "libbinderthreadstate", "libcgrouprc", "libcgrouprc_format", "libcutils", -- cgit v1.2.3-59-g8ed1b From fa247b1870da660a722551d6eb944dab1c8f0b53 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 11 Feb 2020 08:58:26 -0800 Subject: Rename ColorLayer to EffectLayer to handle both shadows and color fill We want the ability for a layer to render shadows without any content. This new layer type will be able to combine effects as needed. Test: presubmit tests (no functional changes) Test: go/wm-smoke Change-Id: I8663d126a23263a3d7dc799d39a9cf44b3b6e4a0 --- libs/gui/include/gui/ISurfaceComposerClient.h | 2 +- libs/gui/tests/BLASTBufferQueue_test.cpp | 2 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 3 +- libs/gui/tests/RegionSampling_test.cpp | 2 +- libs/gui/tests/SamplingDemo.cpp | 6 +- services/surfaceflinger/Android.bp | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/ColorLayer.cpp | 132 --------------------- services/surfaceflinger/ColorLayer.h | 59 --------- services/surfaceflinger/EffectLayer.cpp | 132 +++++++++++++++++++++ services/surfaceflinger/EffectLayer.h | 63 ++++++++++ services/surfaceflinger/Layer.cpp | 8 +- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 16 +-- services/surfaceflinger/SurfaceFlinger.h | 6 +- .../SurfaceFlingerDefaultFactory.cpp | 6 +- .../surfaceflinger/SurfaceFlingerDefaultFactory.h | 2 +- services/surfaceflinger/SurfaceFlingerFactory.h | 4 +- .../tests/LayerRenderTypeTransaction_test.cpp | 20 ++-- .../surfaceflinger/tests/LayerTransactionTest.h | 4 +- .../tests/LayerTypeTransaction_test.cpp | 10 +- services/surfaceflinger/tests/LayerUpdate_test.cpp | 12 +- .../tests/MultiDisplayLayerBounds_test.cpp | 2 +- .../tests/fakehwc/SFFakeHwc_test.cpp | 9 +- .../tests/unittests/CompositionTest.cpp | 34 +++--- .../tests/unittests/RefreshRateSelectionTest.cpp | 16 +-- .../tests/unittests/TestableSurfaceFlinger.h | 6 +- 27 files changed, 283 insertions(+), 279 deletions(-) delete mode 100644 services/surfaceflinger/ColorLayer.cpp delete mode 100644 services/surfaceflinger/ColorLayer.h create mode 100644 services/surfaceflinger/EffectLayer.cpp create mode 100644 services/surfaceflinger/EffectLayer.h (limited to 'libs') diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2b65d2f42d..6366529a10 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -44,7 +44,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceBufferQueue = 0x00000000, - eFXSurfaceColor = 0x00020000, + eFXSurfaceEffect = 0x00020000, eFXSurfaceBufferState = 0x00040000, eFXSurfaceContainer = 0x00080000, eFXSurfaceMask = 0x000F0000, diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index e184c7f33b..a87ccd664e 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -403,7 +403,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { int32_t finalCropSideLength = bufferSideLength / 2; auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; t.setLayerStack(bg, 0) diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 1a623e21dc..c59afba87c 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -82,7 +82,8 @@ public: int width, int height) { sp surfaceControl = scc->createSurface(String8("Test Surface"), 0 /* bufHeight */, 0 /* bufWidth */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect); return std::make_unique(surfaceControl, width, height); } diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index c9de37d957..dbd4ef9d7e 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -183,7 +183,7 @@ protected: mBackgroundLayer = mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); uint32_t layerPositionBottom = 0x7E000000; SurfaceComposerClient::Transaction{} .setLayer(mBackgroundLayer, layerPositionBottom) diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index 9891587fe2..5c1bebb960 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -39,7 +39,7 @@ public: sp client = new SurfaceComposerClient; mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); const int32_t width = samplingArea.getWidth(); const int32_t height = samplingArea.getHeight(); @@ -55,7 +55,7 @@ public: .apply(); mButtonBlend = client->createSurface(String8(name) + "Blend", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mButtonBlend, 0x7ffffffe) @@ -73,7 +73,7 @@ public: if (HIGHLIGHT_SAMPLING_AREA) { mSamplingArea = client->createSurface(String8("SamplingArea"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); SurfaceComposerClient::Transaction{} .setLayer(mSamplingArea, 0x7ffffffd) diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 1b1e8890ab..4ffdf9761e 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -136,7 +136,7 @@ filegroup { "BufferStateLayer.cpp", "ClientCache.cpp", "Client.cpp", - "ColorLayer.cpp", + "EffectLayer.cpp", "ContainerLayer.cpp", "DisplayDevice.cpp", "DisplayHardware/ComposerHal.cpp", diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 923a81c093..6e0d13a732 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -32,7 +32,7 @@ #include #include -#include "ColorLayer.h" +#include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "TimeStats/TimeStats.h" diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp deleted file mode 100644 index 83050c4774..0000000000 --- a/services/surfaceflinger/ColorLayer.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -// #define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "ColorLayer" - -#include "ColorLayer.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "DisplayDevice.h" -#include "SurfaceFlinger.h" - -namespace android { -// --------------------------------------------------------------------------- - -ColorLayer::ColorLayer(const LayerCreationArgs& args) - : Layer(args), - mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {} - -ColorLayer::~ColorLayer() = default; - -std::optional ColorLayer::prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - auto result = Layer::prepareClientComposition(targetSettings); - if (!result) { - return result; - } - result->source.solidColor = getColor().rgb; - return result; -} - -bool ColorLayer::isVisible() const { - return !isHiddenByPolicy() && getAlpha() > 0.0_hf; -} - -bool ColorLayer::setColor(const half3& color) { - if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g && - mCurrentState.color.b == color.b) { - return false; - } - - mCurrentState.sequence++; - mCurrentState.color.r = color.r; - mCurrentState.color.g = color.g; - mCurrentState.color.b = color.b; - mCurrentState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -bool ColorLayer::setDataspace(ui::Dataspace dataspace) { - if (mCurrentState.dataspace == dataspace) { - return false; - } - - mCurrentState.sequence++; - mCurrentState.dataspace = dataspace; - mCurrentState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - -void ColorLayer::preparePerFrameCompositionState() { - Layer::preparePerFrameCompositionState(); - - auto* compositionState = editCompositionState(); - compositionState->color = getColor(); - compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; -} - -sp ColorLayer::getCompositionEngineLayerFE() const { - return asLayerFE(); -} - -compositionengine::LayerFECompositionState* ColorLayer::editCompositionState() { - return mCompositionState.get(); -} - -const compositionengine::LayerFECompositionState* ColorLayer::getCompositionState() const { - return mCompositionState.get(); -} - -bool ColorLayer::isOpaque(const Layer::State& s) const { - // Consider the layer to be opaque if its opaque flag is set or its effective - // alpha (considering the alpha of its parents as well) is 1.0; - return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf; -} - -ui::Dataspace ColorLayer::getDataSpace() const { - return mDrawingState.dataspace; -} - -sp ColorLayer::createClone() { - sp layer = mFlinger->getFactory().createColorLayer( - LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, - LayerMetadata())); - layer->setInitialValuesForClone(this); - return layer; -} - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h deleted file mode 100644 index 4deb162191..0000000000 --- a/services/surfaceflinger/ColorLayer.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2007 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 - -#include - -#include "Layer.h" - -namespace android { - -class ColorLayer : public Layer { -public: - explicit ColorLayer(const LayerCreationArgs&); - ~ColorLayer() override; - - sp getCompositionEngineLayerFE() const override; - compositionengine::LayerFECompositionState* editCompositionState() override; - - const char* getType() const override { return "ColorLayer"; } - bool isVisible() const override; - - bool setColor(const half3& color) override; - - bool setDataspace(ui::Dataspace dataspace) override; - - ui::Dataspace getDataSpace() const override; - - bool isOpaque(const Layer::State& s) const override; - -protected: - /* - * compositionengine::LayerFE overrides - */ - const compositionengine::LayerFECompositionState* getCompositionState() const override; - void preparePerFrameCompositionState() override; - std::optional prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - - std::unique_ptr mCompositionState; - - sp createClone() override; -}; - -} // namespace android diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp new file mode 100644 index 0000000000..e928c57929 --- /dev/null +++ b/services/surfaceflinger/EffectLayer.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2007 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. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "EffectLayer" + +#include "EffectLayer.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "DisplayDevice.h" +#include "SurfaceFlinger.h" + +namespace android { +// --------------------------------------------------------------------------- + +EffectLayer::EffectLayer(const LayerCreationArgs& args) + : Layer(args), + mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} {} + +EffectLayer::~EffectLayer() = default; + +std::optional EffectLayer::prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + auto result = Layer::prepareClientComposition(targetSettings); + if (!result) { + return result; + } + result->source.solidColor = getColor().rgb; + return result; +} + +bool EffectLayer::isVisible() const { + return !isHiddenByPolicy() && getAlpha() > 0.0_hf; +} + +bool EffectLayer::setColor(const half3& color) { + if (mCurrentState.color.r == color.r && mCurrentState.color.g == color.g && + mCurrentState.color.b == color.b) { + return false; + } + + mCurrentState.sequence++; + mCurrentState.color.r = color.r; + mCurrentState.color.g = color.g; + mCurrentState.color.b = color.b; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool EffectLayer::setDataspace(ui::Dataspace dataspace) { + if (mCurrentState.dataspace == dataspace) { + return false; + } + + mCurrentState.sequence++; + mCurrentState.dataspace = dataspace; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + +void EffectLayer::preparePerFrameCompositionState() { + Layer::preparePerFrameCompositionState(); + + auto* compositionState = editCompositionState(); + compositionState->color = getColor(); + compositionState->compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR; +} + +sp EffectLayer::getCompositionEngineLayerFE() const { + return asLayerFE(); +} + +compositionengine::LayerFECompositionState* EffectLayer::editCompositionState() { + return mCompositionState.get(); +} + +const compositionengine::LayerFECompositionState* EffectLayer::getCompositionState() const { + return mCompositionState.get(); +} + +bool EffectLayer::isOpaque(const Layer::State& s) const { + // Consider the layer to be opaque if its opaque flag is set or its effective + // alpha (considering the alpha of its parents as well) is 1.0; + return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf; +} + +ui::Dataspace EffectLayer::getDataSpace() const { + return mDrawingState.dataspace; +} + +sp EffectLayer::createClone() { + sp layer = mFlinger->getFactory().createEffectLayer( + LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, + LayerMetadata())); + layer->setInitialValuesForClone(this); + return layer; +} + +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/EffectLayer.h b/services/surfaceflinger/EffectLayer.h new file mode 100644 index 0000000000..8694283760 --- /dev/null +++ b/services/surfaceflinger/EffectLayer.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 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 + +#include + +#include "Layer.h" + +namespace android { + +// A layer that can render a combination of the following effects. +// * fill the bounds of the layer with a color +// * render a shadow cast by the bounds of the layer +// If no effects are enabled, the layer is considered to be invisible. +class EffectLayer : public Layer { +public: + explicit EffectLayer(const LayerCreationArgs&); + ~EffectLayer() override; + + sp getCompositionEngineLayerFE() const override; + compositionengine::LayerFECompositionState* editCompositionState() override; + + const char* getType() const override { return "EffectLayer"; } + bool isVisible() const override; + + bool setColor(const half3& color) override; + + bool setDataspace(ui::Dataspace dataspace) override; + + ui::Dataspace getDataSpace() const override; + + bool isOpaque(const Layer::State& s) const override; + +protected: + /* + * compositionengine::LayerFE overrides + */ + const compositionengine::LayerFECompositionState* getCompositionState() const override; + void preparePerFrameCompositionState() override; + std::optional prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) override; + + std::unique_ptr mCompositionState; + + sp createClone() override; +}; + +} // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index effbed67b8..8eb5c22fa8 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -56,10 +56,10 @@ #include #include "BufferLayer.h" -#include "ColorLayer.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" +#include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "LayerProtoHelper.h" #include "LayerRejecter.h" @@ -165,7 +165,7 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp c /* * onLayerDisplayed is only meaningful for BufferLayer, but, is called through * Layer. So, the implementation is done in BufferLayer. When called on a - * ColorLayer object, it's essentially a NOP. + * EffectLayer object, it's essentially a NOP. */ void Layer::onLayerDisplayed(const sp& /*releaseFence*/) {} @@ -1092,9 +1092,9 @@ bool Layer::setBackgroundColor(const half3& color, float alpha, ui::Dataspace da if (!mCurrentState.bgColorLayer && alpha != 0) { // create background color layer if one does not yet exist - uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor; + uint32_t flags = ISurfaceComposerClient::eFXSurfaceEffect; std::string name = mName + "BackgroundColorLayer"; - mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer( + mCurrentState.bgColorLayer = mFlinger->getFactory().createEffectLayer( LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags, LayerMetadata())); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index de4a08070c..a249726739 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -212,7 +212,7 @@ public: InputWindowInfo inputInfo; wp touchableRegionCrop; - // dataspace is only used by BufferStateLayer and ColorLayer + // dataspace is only used by BufferStateLayer and EffectLayer ui::Dataspace dataspace; // The fields below this point are only used by BufferStateLayer diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e8c7a55bc6..55166c0ab3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -83,10 +83,10 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "Client.h" -#include "ColorLayer.h" #include "Colorizer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "Layer.h" #include "LayerVector.h" #include "MonitoredProducer.h" @@ -3694,7 +3694,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, std::move(metadata), handle, outTransformHint, &layer); break; - case ISurfaceComposerClient::eFXSurfaceColor: + case ISurfaceComposerClient::eFXSurfaceEffect: // check if buffer size is set for color layer. if (w > 0 || h > 0) { ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)", @@ -3702,8 +3702,8 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie return BAD_VALUE; } - result = createColorLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), handle, &layer); + result = createEffectLayer(client, std::move(uniqueName), w, h, flags, + std::move(metadata), handle, &layer); break; case ISurfaceComposerClient::eFXSurfaceContainer: // check if buffer size is set for container layer. @@ -3821,10 +3821,10 @@ status_t SurfaceFlinger::createBufferStateLayer(const sp& client, std::s return NO_ERROR; } -status_t SurfaceFlinger::createColorLayer(const sp& client, std::string name, uint32_t w, - uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* handle, sp* outLayer) { - *outLayer = getFactory().createColorLayer( +status_t SurfaceFlinger::createEffectLayer(const sp& client, std::string name, uint32_t w, + uint32_t h, uint32_t flags, LayerMetadata metadata, + sp* handle, sp* outLayer) { + *outLayer = getFactory().createEffectLayer( {this, client, std::move(name), w, h, flags, std::move(metadata)}); *handle = (*outLayer)->getHandle(); return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ccf57946ab..3a48bdadff 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -648,9 +648,9 @@ private: sp* outHandle, uint32_t* outTransformHint, sp* outLayer); - status_t createColorLayer(const sp& client, std::string name, uint32_t w, uint32_t h, - uint32_t flags, LayerMetadata metadata, sp* outHandle, - sp* outLayer); + status_t createEffectLayer(const sp& client, std::string name, uint32_t w, uint32_t h, + uint32_t flags, LayerMetadata metadata, sp* outHandle, + sp* outLayer); status_t createContainerLayer(const sp& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index f9658a78d6..d49133d1fc 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -25,9 +25,9 @@ #include "BufferLayerConsumer.h" #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "Layer.h" #include "MonitoredProducer.h" #include "NativeWindowSurface.h" @@ -139,8 +139,8 @@ sp DefaultFactory::createBufferStateLayer(const LayerCreationA return new BufferStateLayer(args); } -sp DefaultFactory::createColorLayer(const LayerCreationArgs& args) { - return new ColorLayer(args); +sp DefaultFactory::createEffectLayer(const LayerCreationArgs& args) { + return new EffectLayer(args); } } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 36fae217ce..89194c7ad1 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -55,7 +55,7 @@ public: std::unique_ptr createCompositionEngine() override; sp createBufferQueueLayer(const LayerCreationArgs& args) override; sp createBufferStateLayer(const LayerCreationArgs& args) override; - sp createColorLayer(const LayerCreationArgs& args) override; + sp createEffectLayer(const LayerCreationArgs& args) override; sp createContainerLayer(const LayerCreationArgs& args) override; }; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 951bd09293..1eab3b1302 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -31,7 +31,7 @@ typedef int32_t PixelFormat; class BufferQueueLayer; class BufferStateLayer; class BufferLayerConsumer; -class ColorLayer; +class EffectLayer; class ContainerLayer; class DisplayDevice; class DispSync; @@ -104,7 +104,7 @@ public: virtual sp createBufferQueueLayer(const LayerCreationArgs& args) = 0; virtual sp createBufferStateLayer(const LayerCreationArgs& args) = 0; - virtual sp createColorLayer(const LayerCreationArgs& args) = 0; + virtual sp createEffectLayer(const LayerCreationArgs& args) = 0; virtual sp createContainerLayer(const LayerCreationArgs& args) = 0; protected: diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index 24874b010b..6c8eb27bd0 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -531,7 +531,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) @@ -570,7 +570,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType Color priorBgColor = Color::BLUE; Color expectedColor = Color::BLACK; switch (layerType) { - case ISurfaceComposerClient::eFXSurfaceColor: + case ISurfaceComposerClient::eFXSurfaceEffect: ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType)); Transaction() .setCrop_legacy(layer, Rect(0, 0, width, height)) @@ -599,7 +599,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType return; } - if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) { + if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) { Transaction() .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN) .apply(); @@ -628,7 +628,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) { bool bufferFill = false; float alpha = 1.0f; Color finalColor = Color::RED; - ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor, + ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect, priorColor, bufferFill, alpha, finalColor)); } @@ -744,7 +744,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) { sp colorLayer; ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f)) @@ -760,7 +760,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); @@ -787,7 +787,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32)); ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply(); const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f); const float alpha = 0.25f; @@ -1663,7 +1663,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { sp colorLayer; ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor)); + ISurfaceComposerClient::eFXSurfaceEffect)); Transaction() .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)) .setLayer(colorLayer, mLayerZBase + 1) @@ -1719,7 +1719,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) { ISurfaceComposerClient::eFXSurfaceContainer)); ASSERT_NO_FATAL_FAILURE( colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get())); + ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get())); Transaction() .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100)) @@ -1780,7 +1780,7 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) { ISurfaceComposerClient::eFXSurfaceContainer)); ASSERT_NO_FATAL_FAILURE( colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get())); + ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get())); Transaction() .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100)) diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 5eb1739219..932c7c86fa 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -89,7 +89,7 @@ protected: SurfaceControl* parent = nullptr) { auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, parent); + ISurfaceComposerClient::eFXSurfaceEffect, parent); asTransaction([&](Transaction& t) { t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}); t.setAlpha(colorLayer, color.a / 255.0f); @@ -268,7 +268,7 @@ private: mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); // set layer stack (b/68888219) Transaction t; diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp index 7e9202bb82..84780ba73b 100644 --- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp @@ -69,13 +69,13 @@ TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) { TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) { sp parent = LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp childLayer; ASSERT_NO_FATAL_FAILURE( childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, + ISurfaceComposerClient::eFXSurfaceEffect, parent.get())); Transaction() .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) @@ -116,17 +116,17 @@ TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) { TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) { sp parent = LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp relativeParent = LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor); + ISurfaceComposerClient::eFXSurfaceEffect); sp childLayer; ASSERT_NO_FATAL_FAILURE( childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */, 0 /* buffer height */, - ISurfaceComposerClient::eFXSurfaceColor, + ISurfaceComposerClient::eFXSurfaceEffect, parent.get())); Transaction() .setColor(childLayer, half3{1.0f, 0.0f, 0.0f}) diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index a1c412801d..cf3f8e8865 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -1114,7 +1114,7 @@ TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) { TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) { sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get()); + ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setColor(colorLayer, half3{0, 0, 0}); @@ -1139,7 +1139,7 @@ TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) { ASSERT_TRUE(cropLayer->isValid()); sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10)); @@ -1164,7 +1164,7 @@ TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) { TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) { sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get()); + ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setPosition(colorLayer, 320, 320); @@ -1195,7 +1195,7 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) { ASSERT_TRUE(boundlessLayerDownShift->isValid()); sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get()); + ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { t.setPosition(boundlessLayerRightShift, 32, 0); @@ -1229,7 +1229,7 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) { ASSERT_TRUE(boundlessLayer->isValid()); sp colorLayer = mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get()); ASSERT_TRUE(colorLayer != nullptr); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { @@ -1261,7 +1261,7 @@ TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) { ASSERT_TRUE(rootBoundlessLayer->isValid()); sp colorLayer = createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get()); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp index c9fdc3b799..f8a5b4094d 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -66,7 +66,7 @@ protected: void createColorLayer(uint32_t layerStack) { mColorLayer = createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */, - PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor); + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_TRUE(mColorLayer != nullptr); ASSERT_TRUE(mColorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index e75149653c..32c58ad390 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1827,10 +1827,11 @@ class ChildColorLayerTest : public ChildLayerTest { protected: void SetUp() override { Base::SetUp(); - Base::mChild = Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, - PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceColor, - Base::mFGSurfaceControl.get()); + Base::mChild = + Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect, + Base::mFGSurfaceControl.get()); { TransactionScope ts(*Base::sFakeComposer); ts.setColor(Base::mChild, diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 888e009282..6e83166a80 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -35,7 +35,7 @@ #include #include "BufferQueueLayer.h" -#include "ColorLayer.h" +#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -713,7 +713,7 @@ struct BaseLayerProperties { struct DefaultLayerProperties : public BaseLayerProperties {}; -struct ColorLayerProperties : public BaseLayerProperties { +struct EffectLayerProperties : public BaseLayerProperties { static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE; }; @@ -866,16 +866,16 @@ struct BaseLayerVariant { }; template -struct ColorLayerVariant : public BaseLayerVariant { +struct EffectLayerVariant : public BaseLayerVariant { using Base = BaseLayerVariant; - using FlingerLayerType = sp; + using FlingerLayerType = sp; static FlingerLayerType createLayer(CompositionTest* test) { - FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { - return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp(), - "test-layer", LayerProperties::WIDTH, - LayerProperties::HEIGHT, - LayerProperties::LAYER_FLAGS, LayerMetadata())); + FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { + return new EffectLayer( + LayerCreationArgs(test->mFlinger.mFlinger.get(), sp(), "test-layer", + LayerProperties::WIDTH, LayerProperties::HEIGHT, + LayerProperties::LAYER_FLAGS, LayerMetadata())); }); auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); @@ -1228,31 +1228,31 @@ TEST_F(CompositionTest, captureScreenNormalBufferLayer) { * Single-color layers */ -TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) { +TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) { displayRefreshCompositionDirtyGeometry< - CompositionCase, + CompositionCase, KeepCompositionTypeVariant, HwcCompositionResultVariant>>(); } -TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) { +TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) { displayRefreshCompositionDirtyFrame< - CompositionCase, + CompositionCase, KeepCompositionTypeVariant, HwcCompositionResultVariant>>(); } -TEST_F(CompositionTest, REComposedColorLayer) { +TEST_F(CompositionTest, REComposedEffectLayer) { displayRefreshCompositionDirtyFrame< - CompositionCase, + CompositionCase, ChangeCompositionTypeVariant, RECompositionResultVariant>>(); } -TEST_F(CompositionTest, captureScreenColorLayer) { +TEST_F(CompositionTest, captureScreenEffectLayer) { captureScreenComposition< - CompositionCase, + CompositionCase, NoCompositionTypeVariant, REScreenshotResultVariant>>(); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp index cffdc14df7..edd9de46ab 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp @@ -27,7 +27,7 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" +#include "EffectLayer.h" #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" @@ -68,7 +68,7 @@ protected: void setupComposer(int virtualDisplayCount); sp createBufferQueueLayer(); sp createBufferStateLayer(); - sp createColorLayer(); + sp createEffectLayer(); void setParent(Layer* child, Layer* parent); void commitTransaction(Layer* layer); @@ -111,11 +111,11 @@ sp RefreshRateSelectionTest::createBufferStateLayer() { return new BufferStateLayer(args); } -sp RefreshRateSelectionTest::createColorLayer() { +sp RefreshRateSelectionTest::createEffectLayer() { sp client; LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS, LayerMetadata()); - return new ColorLayer(args); + return new EffectLayer(args); } void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) { @@ -244,11 +244,11 @@ TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) { ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority()); } -TEST_F(RefreshRateSelectionTest, testPriorityOnColorLayers) { - mParent = createColorLayer(); - mChild = createColorLayer(); +TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) { + mParent = createEffectLayer(); + mChild = createEffectLayer(); setParent(mChild.get(), mParent.get()); - mGrandChild = createColorLayer(); + mGrandChild = createEffectLayer(); setParent(mGrandChild.get(), mChild.get()); ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 798ba766fc..685cfaf450 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -25,9 +25,9 @@ #include "BufferQueueLayer.h" #include "BufferStateLayer.h" -#include "ColorLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" +#include "EffectLayer.h" #include "FakePhaseOffsets.h" #include "Layer.h" #include "NativeWindowSurface.h" @@ -147,9 +147,7 @@ public: return nullptr; } - sp createColorLayer(const LayerCreationArgs&) override { - return nullptr; - } + sp createEffectLayer(const LayerCreationArgs&) override { return nullptr; } sp createContainerLayer(const LayerCreationArgs&) override { return nullptr; -- cgit v1.2.3-59-g8ed1b From 0ede0213baf29864101a82d1db53ebadcf8a16f8 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 11 Feb 2020 11:21:09 -0800 Subject: Kawase blur feedback Test: transaction tests Test: visual Fixes: 149309004 Change-Id: I0e17eaa60b61065107f3c93a85fcc460ed61b83d --- libs/renderengine/gl/filters/KawaseBlurFilter.cpp | 18 ++++++++---------- libs/renderengine/gl/filters/KawaseBlurFilter.h | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp index fc26bccc52..7524c6dfe2 100644 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/gl/filters/KawaseBlurFilter.cpp @@ -106,21 +106,19 @@ string KawaseBlurFilter::getFragmentShader() const { precision mediump float; uniform sampler2D uTexture; - highp uniform vec2 uOffset; + uniform vec2 uOffset; highp in vec2 vUV; out vec4 fragColor; - vec4 kawaseBlur() { - return (texture(uTexture, vec2(-1.0, 1.0) * uOffset + vUV, 0.0) - + texture(uTexture, uOffset + vUV, 0.0) - + texture(uTexture, vec2(1.0, -1.0) * uOffset + vUV, 0.0) - + texture(uTexture, vec2(-1.0) * uOffset + vUV, 0.0)) - * 0.25; - } - void main() { - fragColor = kawaseBlur(); + fragColor = texture(uTexture, vUV, 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); + fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); + + fragColor = vec4(fragColor.rgb * 0.2, 1.0); } )SHADER"; } diff --git a/libs/renderengine/gl/filters/KawaseBlurFilter.h b/libs/renderengine/gl/filters/KawaseBlurFilter.h index ec81f81229..20009cf9bb 100644 --- a/libs/renderengine/gl/filters/KawaseBlurFilter.h +++ b/libs/renderengine/gl/filters/KawaseBlurFilter.h @@ -30,7 +30,7 @@ namespace gl { class KawaseBlurFilter : public BlurFilter { public: - static constexpr uint32_t kMaxPasses = 8; + static constexpr uint32_t kMaxPasses = 6; explicit KawaseBlurFilter(GLESRenderEngine& engine); status_t prepare() override; -- cgit v1.2.3-59-g8ed1b From 3248ea00de2c2c593d557ad6760bcfe9e5c2a96d Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 11 Feb 2020 17:27:38 -0800 Subject: Define out the hwbinder death notifier code for libgui This code is only needed for the NO_BINDER version of libgui (libgui_bufferqueue_static). For libgui, the notifier is linked inside the connect/disconnect call of BufferQueue itself. bug: 149345887 test: Android Auto team helped test it on Auto devices to fix the bug. Change-Id: I29ab83b9119729e3b878ace439086e87d9c585f6 --- libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp index 0f3ae2e28c..c76d771262 100644 --- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp @@ -288,10 +288,12 @@ Return B2HGraphicBufferProducer::connect( &bOutput), &hStatus) && b2h(bOutput, &hOutput); - if (converted) { +#ifdef NO_BINDER + if (converted && hListener != nullptr) { mObituary = new Obituary(this, hListener, hConnectionType); hListener->linkToDeath(mObituary, 0); } +#endif // NO_BINDER _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput); return {}; } @@ -304,10 +306,12 @@ Return B2HGraphicBufferProducer::disconnect( } HStatus hStatus{}; bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus); +#ifdef NO_BINDER if (mObituary != nullptr) { mObituary->listener->unlinkToDeath(mObituary); mObituary.clear(); } +#endif // NO_BINDER return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; } -- cgit v1.2.3-59-g8ed1b From 54d3e189009e4138ec5074b0ac79f56ce322daed Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 15 Jan 2020 17:38:38 -0800 Subject: Add verifyInputEvent api to InputDispatcher Now InputDispatcher will be able to check whether a certain InputEvent is legitimate. Use the 'verifyInputEvent' api to determine if a given 'InputEvent' actually came from InputDispatcher. Bug: 134977432 Test: atest VerifiedKeyEventTest VerifiedMotionEventTest libinput_tests inputflinger_tests Change-Id: I8e7fa9bfa3c14b0b0d949fb5e28b43ff7583398f --- include/input/Input.h | 62 +++++++++++ libs/input/Input.cpp | 24 +++++ libs/input/tests/Android.bp | 2 +- libs/input/tests/InputEvent_test.cpp | 1 - .../input/tests/InputPublisherAndConsumer_test.cpp | 1 + libs/input/tests/StructLayout_test.cpp | 30 ++++++ libs/input/tests/VerifiedInputEvent_test.cpp | 116 +++++++++++++++++++++ .../inputflinger/dispatcher/InputDispatcher.cpp | 4 + services/inputflinger/dispatcher/InputDispatcher.h | 2 + .../dispatcher/include/InputDispatcherInterface.h | 7 ++ 10 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 libs/input/tests/VerifiedInputEvent_test.cpp (limited to 'libs') diff --git a/include/input/Input.h b/include/input/Input.h index cf0814cf2f..14a7288d19 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -73,6 +73,19 @@ enum { AMOTION_EVENT_FLAG_TAINTED = 0x80000000, }; +/** + * Allowed VerifiedKeyEvent flags. All other flags from KeyEvent do not get verified. + * These values must be kept in sync with VerifiedKeyEvent.java + */ +constexpr int32_t VERIFIED_KEY_EVENT_FLAGS = AKEY_EVENT_FLAG_CANCELED; + +/** + * Allowed VerifiedMotionEventFlags. All other flags from MotionEvent do not get verified. + * These values must be kept in sync with VerifiedMotionEvent.java + */ +constexpr int32_t VERIFIED_MOTION_EVENT_FLAGS = + AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + enum { /* Used when a motion event is not associated with any display. * Typically used for non-pointer events. */ @@ -718,6 +731,55 @@ protected: bool mInTouchMode; }; +/** + * Base class for verified events. + * Do not create a VerifiedInputEvent explicitly. + * Use helper functions to create them from InputEvents. + */ +struct __attribute__((__packed__)) VerifiedInputEvent { + enum class Type : int32_t { + KEY = AINPUT_EVENT_TYPE_KEY, + MOTION = AINPUT_EVENT_TYPE_MOTION, + }; + + Type type; + int32_t deviceId; + nsecs_t eventTimeNanos; + uint32_t source; + int32_t displayId; +}; + +/** + * Same as KeyEvent, but only contains the data that can be verified. + * If you update this class, you must also update VerifiedKeyEvent.java + */ +struct __attribute__((__packed__)) VerifiedKeyEvent : public VerifiedInputEvent { + int32_t action; + nsecs_t downTimeNanos; + int32_t flags; + int32_t keyCode; + int32_t scanCode; + int32_t metaState; + int32_t repeatCount; +}; + +/** + * Same as MotionEvent, but only contains the data that can be verified. + * If you update this class, you must also update VerifiedMotionEvent.java + */ +struct __attribute__((__packed__)) VerifiedMotionEvent : public VerifiedInputEvent { + float rawX; + float rawY; + int32_t actionMasked; + nsecs_t downTimeNanos; + int32_t flags; + int32_t metaState; + int32_t buttonState; +}; + +VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event); +VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event); + /* * Input event factory. */ diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 85b0fd0ec7..2a73dc0149 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -57,6 +57,30 @@ const char* inputEventTypeToString(int32_t type) { return "UNKNOWN"; } +VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { + return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), + event.getSource(), event.getDisplayId()}, + event.getAction(), + event.getDownTime(), + event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, + event.getKeyCode(), + event.getScanCode(), + event.getMetaState(), + event.getRepeatCount()}; +} + +VerifiedMotionEvent verifiedMotionEventFromMotionEvent(const MotionEvent& event) { + return {{VerifiedInputEvent::Type::MOTION, event.getDeviceId(), event.getEventTime(), + event.getSource(), event.getDisplayId()}, + event.getRawX(0), + event.getRawY(0), + event.getActionMasked(), + event.getDownTime(), + event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, + event.getMetaState(), + event.getButtonState()}; +} + void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac) { mDeviceId = deviceId; diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index c1c35e1b89..fb21d5e3b1 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -10,12 +10,12 @@ cc_test { "LatencyStatistics_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", + "VerifiedInputEvent_test.cpp", ], cflags: [ "-Wall", "-Wextra", "-Werror", - "-Wno-unused-variable", ], shared_libs: [ "libinput", diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index dce1f29124..d0f761887a 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -46,7 +46,6 @@ TEST_F(PointerCoordsTest, ClearSetsBitsToZero) { } TEST_F(PointerCoordsTest, AxisValues) { - float* valuePtr; PointerCoords coords; coords.clear(); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index d4bbf6c6ac..885196f3f3 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -38,6 +38,7 @@ protected: virtual void SetUp() { status_t result = InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); + ASSERT_EQ(OK, result); mPublisher = new InputPublisher(serverChannel); mConsumer = new InputConsumer(clientChannel); diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp index aa8a2d488f..dd127fcabd 100644 --- a/libs/input/tests/StructLayout_test.cpp +++ b/libs/input/tests/StructLayout_test.cpp @@ -98,4 +98,34 @@ void TestBodySize() { static_assert(sizeof(InputMessage::Body::Focus) == 8); } +// --- VerifiedInputEvent --- +// Ensure that VerifiedInputEvent, VerifiedKeyEvent, VerifiedMotionEvent are packed. +// We will treat them as byte collections when signing them. There should not be any uninitialized +// data in-between fields. Otherwise, the padded data will affect the hmac value and verifications +// will fail. + +void TestVerifiedEventSize() { + // VerifiedInputEvent + constexpr size_t VERIFIED_INPUT_EVENT_SIZE = sizeof(VerifiedInputEvent::type) + + sizeof(VerifiedInputEvent::deviceId) + sizeof(VerifiedInputEvent::eventTimeNanos) + + sizeof(VerifiedInputEvent::source) + sizeof(VerifiedInputEvent::displayId); + static_assert(sizeof(VerifiedInputEvent) == VERIFIED_INPUT_EVENT_SIZE); + + // VerifiedKeyEvent + constexpr size_t VERIFIED_KEY_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE + + sizeof(VerifiedKeyEvent::action) + sizeof(VerifiedKeyEvent::downTimeNanos) + + sizeof(VerifiedKeyEvent::flags) + sizeof(VerifiedKeyEvent::keyCode) + + sizeof(VerifiedKeyEvent::scanCode) + sizeof(VerifiedKeyEvent::metaState) + + sizeof(VerifiedKeyEvent::repeatCount); + static_assert(sizeof(VerifiedKeyEvent) == VERIFIED_KEY_EVENT_SIZE); + + // VerifiedMotionEvent + constexpr size_t VERIFIED_MOTION_EVENT_SIZE = VERIFIED_INPUT_EVENT_SIZE + + sizeof(VerifiedMotionEvent::rawX) + sizeof(VerifiedMotionEvent::rawY) + + sizeof(VerifiedMotionEvent::actionMasked) + sizeof(VerifiedMotionEvent::downTimeNanos) + + sizeof(VerifiedMotionEvent::flags) + sizeof(VerifiedMotionEvent::metaState) + + sizeof(VerifiedMotionEvent::buttonState); + static_assert(sizeof(VerifiedMotionEvent) == VERIFIED_MOTION_EVENT_SIZE); +} + } // namespace android diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp new file mode 100644 index 0000000000..a59dbe5987 --- /dev/null +++ b/libs/input/tests/VerifiedInputEvent_test.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace android { + +static KeyEvent getKeyEventWithFlags(int32_t flags) { + KeyEvent event; + event.initialize(2 /*deviceId*/, AINPUT_SOURCE_GAMEPAD, ADISPLAY_ID_DEFAULT, INVALID_HMAC, + AKEY_EVENT_ACTION_DOWN, flags, AKEYCODE_BUTTON_X, 121 /*scanCode*/, + AMETA_ALT_ON, 1 /*repeatCount*/, 1000 /*downTime*/, 2000 /*eventTime*/); + return event; +} + +static MotionEvent getMotionEventWithFlags(int32_t flags) { + MotionEvent event; + constexpr size_t pointerCount = 1; + PointerProperties pointerProperties[pointerCount]; + PointerCoords pointerCoords[pointerCount]; + for (size_t i = 0; i < pointerCount; i++) { + pointerProperties[i].clear(); + pointerProperties[i].id = i; + pointerCoords[i].clear(); + } + + event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, INVALID_HMAC, + AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags, + AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, 2 /*xScale*/, 3 /*yScale*/, 4 /*xOffset*/, + 5 /*yOffset*/, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/, 280 /*xCursorPosition*/, + 540 /*yCursorPosition*/, 100 /*downTime*/, 200 /*eventTime*/, pointerCount, + pointerProperties, pointerCoords); + return event; +} + +TEST(VerifiedKeyEventTest, ConvertKeyEventToVerifiedKeyEvent) { + KeyEvent event = getKeyEventWithFlags(0); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + + ASSERT_EQ(VerifiedInputEvent::Type::KEY, verified.type); + + ASSERT_EQ(event.getDeviceId(), verified.deviceId); + ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos); + ASSERT_EQ(event.getSource(), verified.source); + ASSERT_EQ(event.getDisplayId(), verified.displayId); + + ASSERT_EQ(event.getAction(), verified.action); + ASSERT_EQ(event.getDownTime(), verified.downTimeNanos); + ASSERT_EQ(event.getFlags() & VERIFIED_KEY_EVENT_FLAGS, verified.flags); + ASSERT_EQ(event.getKeyCode(), verified.keyCode); + ASSERT_EQ(event.getScanCode(), verified.scanCode); + ASSERT_EQ(event.getMetaState(), verified.metaState); + ASSERT_EQ(event.getRepeatCount(), verified.repeatCount); +} + +TEST(VerifiedKeyEventTest, VerifiedKeyEventContainsOnlyVerifiedFlags) { + KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_FALLBACK); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + ASSERT_EQ(AKEY_EVENT_FLAG_CANCELED, verified.flags); +} + +TEST(VerifiedKeyEventTest, VerifiedKeyEventDoesNotContainUnverifiedFlags) { + KeyEvent event = getKeyEventWithFlags(AKEY_EVENT_FLAG_EDITOR_ACTION); + VerifiedKeyEvent verified = verifiedKeyEventFromKeyEvent(event); + ASSERT_EQ(0, verified.flags); +} + +TEST(VerifiedMotionEventTest, ConvertMotionEventToVerifiedMotionEvent) { + MotionEvent event = getMotionEventWithFlags(0); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + + ASSERT_EQ(VerifiedInputEvent::Type::MOTION, verified.type); + + ASSERT_EQ(event.getDeviceId(), verified.deviceId); + ASSERT_EQ(event.getEventTime(), verified.eventTimeNanos); + ASSERT_EQ(event.getSource(), verified.source); + ASSERT_EQ(event.getDisplayId(), verified.displayId); + + ASSERT_EQ(event.getRawX(0), verified.rawX); + ASSERT_EQ(event.getRawY(0), verified.rawY); + ASSERT_EQ(event.getAction(), verified.actionMasked); + ASSERT_EQ(event.getDownTime(), verified.downTimeNanos); + ASSERT_EQ(event.getFlags() & VERIFIED_MOTION_EVENT_FLAGS, verified.flags); + ASSERT_EQ(event.getMetaState(), verified.metaState); + ASSERT_EQ(event.getButtonState(), verified.buttonState); +} + +TEST(VerifiedMotionEventTest, VerifiedMotionEventContainsOnlyVerifiedFlags) { + MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | + AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, verified.flags); +} + +TEST(VerifiedMotionEventTest, VerifiedMotionEventDoesNotContainUnverifiedFlags) { + MotionEvent event = getMotionEventWithFlags(AMOTION_EVENT_FLAG_TAINTED); + VerifiedMotionEvent verified = verifiedMotionEventFromMotionEvent(event); + ASSERT_EQ(0, verified.flags); +} + +} // namespace android diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index f2b95e7f7a..a8158ba3cf 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3340,6 +3340,10 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec return injectionResult; } +std::unique_ptr InputDispatcher::verifyInputEvent(const InputEvent& event) { + return nullptr; +} + bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { return injectorUid == 0 || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index d2aea80069..72511e9bf2 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -96,6 +96,8 @@ public: int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) override; + virtual std::unique_ptr verifyInputEvent(const InputEvent& event) override; + virtual void setInputWindows( const std::vector>& inputWindowHandles, int32_t displayId, const sp& setInputWindowsListener = nullptr) override; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 3424f4ce84..6e986768fc 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -92,6 +92,13 @@ public: int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) = 0; + /* + * Check whether InputEvent actually happened by checking the signature of the event. + * + * Return nullptr if the event cannot be verified. + */ + virtual std::unique_ptr verifyInputEvent(const InputEvent& event) = 0; + /* Sets the list of input windows. * * This method may be called on any thread (usually by the input manager). -- cgit v1.2.3-59-g8ed1b From 0188adf4c1f9d0285cb270cf6cc93afca0c586a8 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 13 Feb 2020 08:29:20 -0800 Subject: Only process passback transactions during onFrameAvailable A callback will be fired from the rendering thread when drawFrame returns after queueBuffer. Since the client expects the transaction, if sent, to be populated with the desired frame at this time, we need to make that call to queueBuffer wait until the frame has actually been processed and not put on the shadow queue Step 1 in resolving screen freeze Bug: 149315421 Test: build, boot, turn BLAST ON & reboot & phone boots fine Change-Id: Ibef45fe6c7e0b57fdc4a1be61e2ac93fb2d33525 --- libs/gui/BLASTBufferQueue.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e2f5d31d00..f6493bf9c7 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -174,7 +174,9 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) { + mCallbackCV.wait(_lock); + } + } // add to shadow queue mNumFrameAvailable++; processNextBufferLocked(); -- cgit v1.2.3-59-g8ed1b From ef0b153009c04608ac2316d247ab70009c338e9c Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 17 Dec 2019 09:39:07 -0800 Subject: [ANativeWindow] Add getLastQueuedBuffer api Bug: 137012798 Bug: 148962594 Test: builds Change-Id: I3dcf6741c8d5dc62b7ae13d5cf5dc56173f95660 --- libs/gui/Surface.cpp | 27 +++++++++++++++++++++++++++ libs/gui/include/gui/Surface.h | 1 + libs/nativewindow/include/system/window.h | 31 +++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) (limited to 'libs') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 23532e7e38..278cc593b7 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1180,6 +1180,9 @@ int Surface::perform(int operation, va_list args) allocateBuffers(); res = NO_ERROR; break; + case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: + res = dispatchGetLastQueuedBuffer(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1452,6 +1455,30 @@ int Surface::dispatchAddQueueInterceptor(va_list args) { return NO_ERROR; } +int Surface::dispatchGetLastQueuedBuffer(va_list args) { + AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**); + int* fence = va_arg(args, int*); + float* matrix = va_arg(args, float*); + sp graphicBuffer; + sp spFence; + + int result = mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, matrix); + + if (graphicBuffer != nullptr) { + *buffer = reinterpret_cast(graphicBuffer.get()); + AHardwareBuffer_acquire(*buffer); + } else { + *buffer = nullptr; + } + + if (spFence != nullptr) { + *fence = spFence->dup(); + } else { + *fence = -1; + } + return result; +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 0139507101..4a353fc659 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -262,6 +262,7 @@ private: int dispatchAddDequeueInterceptor(va_list args); int dispatchAddPerformInterceptor(va_list args); int dispatchAddQueueInterceptor(va_list args); + int dispatchGetLastQueuedBuffer(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 121374b1d5..f686147a5f 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -253,6 +253,7 @@ enum { NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, /* private */ NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */ NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ // clang-format on }; @@ -1018,4 +1019,34 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate); } +// ------------------------------------------------------------------------------------------------ +// Candidates for APEX visibility +// These functions are planned to be made stable for APEX modules, but have not +// yet been stabilized to a specific api version. +// ------------------------------------------------------------------------------------------------ + +/** + * Retrieves the last queued buffer for this window, along with the fence that + * fires when the buffer is ready to be read, and the 4x4 coordinate + * transform matrix that should be applied to the buffer's content. The + * transform matrix is represented in column-major order. + * + * If there was no buffer previously queued, then outBuffer will be NULL and + * the value of outFence will be -1. + * + * Note that if outBuffer is not NULL, then the caller will hold a reference + * onto the buffer. Accordingly, the caller must call AHardwareBuffer_release + * when the buffer is no longer needed so that the system may reclaim the + * buffer. + * + * \return NO_ERROR on success. + * \return NO_MEMORY if there was insufficient memory. + */ +static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window, + AHardwareBuffer** outBuffer, int* outFence, + float outTransformMatrix[16]) { + return window->perform(window, NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER, outBuffer, outFence, + outTransformMatrix); +} + __END_DECLS -- cgit v1.2.3-59-g8ed1b From 65b8e8729104d4f7a379d72cdff06036b569dd9b Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 13 Feb 2020 09:45:14 -0800 Subject: Move maxAcquired back to 1 and set maxDequeued BufferQueue internally already limits number of acquired buffers to be 1 more than the maxAcquired set. We want to be able to acquire 2, so setting back to 1. Enable triple buffering through maxDequeuedCount. Bug: 146345307 Test: build, boot, turn BLAST ON, run manually, libgui_test Change-Id: I1deff382da3b37a2bde840802fdc4c10a8b868ed --- libs/gui/BLASTBufferQueue.cpp | 10 ++++++++-- libs/gui/include/gui/BLASTBufferQueue.h | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index e2f5d31d00..4bbc855642 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -19,6 +19,8 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include + #include #include #include @@ -99,7 +101,11 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, mHeight(height), mNextTransaction(nullptr) { BufferQueue::createBufferQueue(&mProducer, &mConsumer); - mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS); + + int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0); + if (!disableTripleBuffer) { + mProducer->setMaxDequeuedBufferCount(2); + } mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true); static int32_t id = 0; @@ -181,7 +187,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp Date: Thu, 13 Feb 2020 13:57:19 -0800 Subject: [ANativeWindow] allocateBuffers changes * rename allocateBuffers to tryAllocateBuffers to reflect that its a best-effort API * promote to public NDK Bug: 148962594 Test: builds Change-Id: Iff73c2eb7bb07d28ef26b95202257950e9da4627 --- libs/nativewindow/ANativeWindow.cpp | 12 ++++++++---- libs/nativewindow/include/android/native_window.h | 11 +++++++++++ libs/nativewindow/libnativewindow.map.txt | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index a1c9eb806b..98b76fd667 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -165,6 +165,14 @@ int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) { return native_window_set_frame_rate(window, frameRate); } +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return; + } + window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); +} + + /************************************************************************************************** * vndk-stable **************************************************************************************************/ @@ -328,10 +336,6 @@ int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window, return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data); } -void ANativeWindow_allocateBuffers(ANativeWindow* window) { - window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); -} - int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) { return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID); } diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 262aee3501..4b426c518a 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -261,6 +261,17 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN */ int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30); +/** + * Provides a hint to the window that buffers should be preallocated ahead of + * time. Note that the window implementation is not guaranteed to preallocate + * any buffers, for instance if an implementation disallows allocation of new + * buffers, or if there is insufficient memory in the system to preallocate + * additional buffers + * + * Available since API level 30. + */ +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); + #endif // __ANDROID_API__ >= 30 #ifdef __cplusplus diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index e0e20c3ae2..154eb8eb52 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -17,7 +17,6 @@ LIBNATIVEWINDOW { ANativeWindow_OemStorageGet; # llndk ANativeWindow_OemStorageSet; # llndk ANativeWindow_acquire; - ANativeWindow_allocateBuffers; # apex # introduced=30 ANativeWindow_cancelBuffer; # llndk ANativeWindow_dequeueBuffer; # llndk ANativeWindow_getBuffersDataSpace; # introduced=28 @@ -51,6 +50,7 @@ LIBNATIVEWINDOW { ANativeWindow_setSwapInterval; # llndk ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setUsage; # llndk + ANativeWindow_tryAllocateBuffers; # introduced=30 ANativeWindow_unlockAndPost; local: *; -- cgit v1.2.3-59-g8ed1b From 110a0d1b954a129c7b8efddc07d3e85b2b3057a9 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 11 Feb 2020 10:34:28 -0800 Subject: Gaussian blur optimizations Test: transaction tests Test: visual Bug: 149309004 Change-Id: I5ddcd674e7068fa05482b3f6f2eb1efb1c4a4b73 --- libs/renderengine/gl/filters/BlurFilter.cpp | 6 +- .../renderengine/gl/filters/GaussianBlurFilter.cpp | 126 ++++++++++++++------- libs/renderengine/gl/filters/GaussianBlurFilter.h | 9 +- 3 files changed, 95 insertions(+), 46 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index b1a84bd0c2..eb66c8f2a7 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -132,8 +132,7 @@ status_t BlurFilter::render(bool multiPass) { } string BlurFilter::getVertexShader() const { - return R"SHADER( - #version 310 es + return R"SHADER(#version 310 es in vec2 aPosition; in highp vec2 aUV; @@ -147,8 +146,7 @@ string BlurFilter::getVertexShader() const { } string BlurFilter::getMixFragShader() const { - string shader = R"SHADER( - #version 310 es + string shader = R"SHADER(#version 310 es precision mediump float; in highp vec2 vUV; diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp index 4d7bf44540..a0d7af8218 100644 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.cpp +++ b/libs/renderengine/gl/filters/GaussianBlurFilter.cpp @@ -43,7 +43,7 @@ GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine) mVPosLoc = mVerticalProgram.getAttributeLocation("aPosition"); mVUvLoc = mVerticalProgram.getAttributeLocation("aUV"); mVTextureLoc = mVerticalProgram.getUniformLocation("uTexture"); - mVIncrementLoc = mVerticalProgram.getUniformLocation("uIncrement"); + mVGaussianOffsetLoc = mVerticalProgram.getUniformLocation("uGaussianOffsets"); mVNumSamplesLoc = mVerticalProgram.getUniformLocation("uSamples"); mVGaussianWeightLoc = mVerticalProgram.getUniformLocation("uGaussianWeights"); @@ -51,7 +51,7 @@ GaussianBlurFilter::GaussianBlurFilter(GLESRenderEngine& engine) mHPosLoc = mHorizontalProgram.getAttributeLocation("aPosition"); mHUvLoc = mHorizontalProgram.getAttributeLocation("aUV"); mHTextureLoc = mHorizontalProgram.getUniformLocation("uTexture"); - mHIncrementLoc = mHorizontalProgram.getUniformLocation("uIncrement"); + mHGaussianOffsetLoc = mHorizontalProgram.getUniformLocation("uGaussianOffsets"); mHNumSamplesLoc = mHorizontalProgram.getUniformLocation("uSamples"); mHGaussianWeightLoc = mHorizontalProgram.getUniformLocation("uGaussianWeights"); } @@ -60,6 +60,36 @@ void GaussianBlurFilter::allocateTextures() { mVerticalPassFbo.allocateBuffers(mBlurredFbo.getBufferWidth(), mBlurredFbo.getBufferHeight()); } +static void calculateLinearGaussian(uint32_t samples, double dimension, + GLfloat* gaussianLinearOffsets, GLfloat* gaussianWeights, + GLfloat* gaussianLinearWeights) { + // The central point in the symmetric bell curve is not offset. + // This decision allows one less sampling in the GPU. + gaussianLinearWeights[0] = gaussianWeights[0]; + gaussianLinearOffsets[0] = 0.0; + + // Calculate the linear weights. + // This is a vector reduction where an element of the packed reduced array + // contains the sum of two adjacent members of the original packed array. + // We start preserving the element 1 of the array and then perform sum for + // every other (i+=2) element of the gaussianWeights array. + gaussianLinearWeights[1] = gaussianWeights[1]; + const auto start = 1 + ((samples - 1) & 0x1); + for (size_t i = start; i < samples; i += 2) { + gaussianLinearWeights[start + i / 2] = gaussianWeights[i] + gaussianWeights[i + 1]; + } + + // Calculate the texture coordinates offsets as an average of the initial offsets, + // weighted by the Gaussian weights as described in the original article. + gaussianLinearOffsets[1] = 1.0 / dimension; + for (size_t i = start; i < samples; i += 2) { + GLfloat offset_1 = float(i) / dimension; + GLfloat offset_2 = float(i + 1) / dimension; + gaussianLinearOffsets[start + i / 2] = + (offset_1 * gaussianWeights[i] + offset_2 * gaussianWeights[i + 1]) / + gaussianLinearWeights[start + i / 2]; + } +} status_t GaussianBlurFilter::prepare() { ATRACE_NAME("GaussianBlurFilter::prepare"); @@ -88,27 +118,47 @@ status_t GaussianBlurFilter::prepare() { mVerticalPassFbo.bind(); mVerticalProgram.useProgram(); - // Precompute gaussian bell curve, and send it to the shader to avoid - // unnecessary computations. - auto samples = min(mRadius, kNumSamples); + // Precompute gaussian bell curve, and send it to the shader to avoid unnecessary computations. + double radiusD = fmax(1.0, mRadius * kFboScale); + auto samples = int(fmin(radiusD, kNumSamples)); GLfloat gaussianWeights[kNumSamples] = {}; - for (size_t i = 0; i < samples; i++) { - float normalized = float(i) / samples; + + gaussianWeights[0] = 1.0f; + auto totalWeight = gaussianWeights[0]; + + // Gaussian weights calculation. + for (size_t i = 1; i < samples; i++) { + const double normalized = i / radiusD; gaussianWeights[i] = (float)exp(-K * normalized * normalized); + totalWeight += 2.0 * gaussianWeights[i]; + } + + // Gaussian weights normalization to avoid work in the GPU. + for (size_t i = 0; i < samples; i++) { + gaussianWeights[i] /= totalWeight; } - // set uniforms auto width = mVerticalPassFbo.getBufferWidth(); auto height = mVerticalPassFbo.getBufferHeight(); - auto radiusF = fmax(1.0f, mRadius * kFboScale); glViewport(0, 0, width, height); + + // Allocate space for the corrected Gaussian weights and offsets. + // We could use less space, but let's keep the code simple. + GLfloat gaussianLinearWeights[kNumSamples] = {}; + GLfloat gaussianLinearOffsets[kNumSamples] = {}; + + // Calculate the weights and offsets for the vertical pass. + // This only need to be called every time mRadius or height changes, so it could be optimized. + calculateLinearGaussian(samples, double(height), gaussianLinearOffsets, gaussianWeights, + gaussianLinearWeights); + // set uniforms glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mBlurredFbo.getTextureName()); glUniform1i(mVTextureLoc, 0); - glUniform2f(mVIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f)); - glUniform1i(mVNumSamplesLoc, samples); - glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianWeights); - mEngine.checkErrors("Setting vertical-diagonal pass uniforms"); + glUniform1i(mVNumSamplesLoc, 1 + (samples + 1) / 2); + glUniform1fv(mVGaussianWeightLoc, kNumSamples, gaussianLinearWeights); + glUniform1fv(mVGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); + mEngine.checkErrors("Setting vertical pass uniforms"); drawMesh(mVUvLoc, mVPosLoc); @@ -116,14 +166,18 @@ status_t GaussianBlurFilter::prepare() { mBlurredFbo.bind(); mHorizontalProgram.useProgram(); + // Calculate the weights and offsets for the horizontal pass. + // This only needs to be called every time mRadius or width change, so it could be optimized. + calculateLinearGaussian(samples, double(width), gaussianLinearOffsets, gaussianWeights, + gaussianLinearWeights); // set uniforms glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, mVerticalPassFbo.getTextureName()); glUniform1i(mHTextureLoc, 0); - glUniform2f(mHIncrementLoc, radiusF / (width * 2.0f), radiusF / (height * 2.0f)); - glUniform1i(mHNumSamplesLoc, samples); - glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianWeights); - mEngine.checkErrors("Setting vertical pass uniforms"); + glUniform1i(mHNumSamplesLoc, 1 + (samples + 1) / 2); + glUniform1fv(mHGaussianWeightLoc, kNumSamples, gaussianLinearWeights); + glUniform1fv(mHGaussianOffsetLoc, kNumSamples, gaussianLinearOffsets); + mEngine.checkErrors("Setting horizontal pass uniforms"); drawMesh(mHUvLoc, mHPosLoc); @@ -142,43 +196,37 @@ string GaussianBlurFilter::getFragmentShader(bool horizontal) const { stringstream shader; shader << "#version 310 es\n" << "#define DIRECTION " << (horizontal ? "1" : "0") << "\n" - << "#define NUM_SAMPLES " << kNumSamples << + << "#define NUM_SAMPLES " << 1 + (kNumSamples + 1) / 2 << R"SHADER( precision mediump float; uniform sampler2D uTexture; - uniform vec2 uIncrement; uniform float[NUM_SAMPLES] uGaussianWeights; + uniform float[NUM_SAMPLES] uGaussianOffsets; uniform int uSamples; highp in vec2 vUV; out vec4 fragColor; - vec3 gaussianBlur(sampler2D texture, highp vec2 uv, float inc, vec2 direction) { - float totalWeight = 0.0; - vec3 blurred = vec3(0.0); - float fSamples = 1.0 / float(uSamples); - - for (int i = -uSamples; i <= uSamples; i++) { - float weight = uGaussianWeights[abs(i)]; - float normalized = float(i) * fSamples; - float radInc = inc * normalized; - blurred += weight * (texture(texture, radInc * direction + uv, 0.0)).rgb; - totalWeight += weight; - } - - return blurred / totalWeight; - } - void main() { #if DIRECTION == 1 - vec3 color = gaussianBlur(uTexture, vUV, uIncrement.x, vec2(1.0, 0.0)); + const vec2 direction = vec2(1.0, 0.0); #else - vec3 color = gaussianBlur(uTexture, vUV, uIncrement.y, vec2(0.0, 1.0)); + const vec2 direction = vec2(0.0, 1.0); #endif - fragColor = vec4(color, 1.0); - } + // Iteration zero outside loop to avoid sampling the central point twice. + vec4 blurred = uGaussianWeights[0] * (texture(uTexture, vUV, 0.0)); + + // Iterate one side of the bell to halve the loop iterations. + for (int i = 1; i <= uSamples; i++) { + vec2 offset = uGaussianOffsets[i] * direction; + blurred += uGaussianWeights[i] * (texture(uTexture, vUV + offset, 0.0)); + blurred += uGaussianWeights[i] * (texture(uTexture, vUV - offset, 0.0)); + } + + fragColor = vec4(blurred.rgb, 1.0); + } )SHADER"; return shader.str(); } diff --git a/libs/renderengine/gl/filters/GaussianBlurFilter.h b/libs/renderengine/gl/filters/GaussianBlurFilter.h index 8580522f40..44f5fde9f7 100644 --- a/libs/renderengine/gl/filters/GaussianBlurFilter.h +++ b/libs/renderengine/gl/filters/GaussianBlurFilter.h @@ -28,9 +28,12 @@ namespace android { namespace renderengine { namespace gl { +// Class that implements a Gaussian Filter that uses Linear Sampling +// to halve the number of samples and reduce runtime by 40% as described in: +// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling class GaussianBlurFilter : public BlurFilter { public: - static constexpr uint32_t kNumSamples = 12; + static constexpr uint32_t kNumSamples = 22; explicit GaussianBlurFilter(GLESRenderEngine& engine); status_t prepare() override; @@ -47,7 +50,7 @@ private: GLuint mVPosLoc; GLuint mVUvLoc; GLuint mVTextureLoc; - GLuint mVIncrementLoc; + GLuint mVGaussianOffsetLoc; GLuint mVNumSamplesLoc; GLuint mVGaussianWeightLoc; @@ -56,7 +59,7 @@ private: GLuint mHPosLoc; GLuint mHUvLoc; GLuint mHTextureLoc; - GLuint mHIncrementLoc; + GLuint mHGaussianOffsetLoc; GLuint mHNumSamplesLoc; GLuint mHGaussianWeightLoc; }; -- cgit v1.2.3-59-g8ed1b From d41a1be2d7a0a46be45c7f6338b739c49bef824e Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 14 Feb 2020 15:18:11 -0800 Subject: [ANativeWindow] Apply remaining API feedback * move ANativeWindow_getFrameId to a platform api, as native_window_get_frame_timestamps is not stable and therefore the associated api surface is not complete enough to be stable. * Adjust documentation for returned errors. In most cases errors aren't returned in practice. In the case of ANativeWindow_setDequeueTimeout the errors are enumerated explicitly. Bug: 148962594 Test: builds Change-Id: I1ff5113d91fdcfc4679b2862af72fbf811171253 --- libs/nativewindow/ANativeWindow.cpp | 4 ---- libs/nativewindow/include/apex/window.h | 34 ++++++++++--------------------- libs/nativewindow/include/system/window.h | 11 ++++++++++ libs/nativewindow/libnativewindow.map.txt | 1 - 4 files changed, 22 insertions(+), 28 deletions(-) (limited to 'libs') diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 98b76fd667..d0d1114d30 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -335,7 +335,3 @@ int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window, void* data) { return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data); } - -int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) { - return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID); -} diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h index 02b886c4f0..2d1354cdf1 100644 --- a/libs/nativewindow/include/apex/window.h +++ b/libs/nativewindow/include/apex/window.h @@ -173,25 +173,22 @@ int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window, /** * Retrieves how long it took for the last time a buffer was dequeued. * - * \return a negative value on error, otherwise returns the duration in - * nanoseconds + * \return the dequeue duration in nanoseconds */ int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window); /** * Retrieves how long it took for the last time a buffer was queued. * - * \return a negative value on error, otherwise returns the duration in - * nanoseconds. + * \return the queue duration in nanoseconds */ int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window); /** * Retrieves the system time in nanoseconds when the last time a buffer - * was dequeued. + * started to be dequeued. * - * \return a negative value on error, otherwise returns the duration in - * nanoseconds. + * \return the start time in nanoseconds */ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); @@ -200,23 +197,14 @@ int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window); * made by the window will return -ETIMEDOUT after the timeout if the dequeue * takes too long. * - * \return NO_ERROR on success, -errno on error. - */ -int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout); - -/** - * Provides a hint to the window that buffers should be preallocated ahead of - * time. Note that the window implementation is not guaranteed to preallocate - * any buffers, for instance if a private API disallows allocation of new - * buffers. As such no success/error status is returned. - */ -void ANativeWindow_allocateBuffers(ANativeWindow* window); - -/** - * Retrieves an identifier for the next frame to be queued by this window. + * If the provided timeout is negative, hen this removes the previously configured + * timeout. The window then behaves as if ANativeWindow_setDequeueTimeout was + * never called. * - * \return -errno on error, otherwise returns the next frame id. + * \return NO_ERROR on success + * \return BAD_VALUE if the dequeue timeout was unabled to be updated, as + * updating the dequeue timeout may change internals of the underlying window. */ -int64_t ANativeWindow_getNextFrameId(ANativeWindow* window); +int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout); __END_DECLS diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index f686147a5f..c791b61753 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1049,4 +1049,15 @@ static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window, outTransformMatrix); } +/** + * Retrieves an identifier for the next frame to be queued by this window. + * + * \return the next frame id. + */ +static inline int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) { + int64_t value; + window->perform(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID, &value); + return value; +} + __END_DECLS diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 154eb8eb52..35f0627e90 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -25,7 +25,6 @@ LIBNATIVEWINDOW { ANativeWindow_getLastDequeueDuration; # apex # introduced=30 ANativeWindow_getLastDequeueStartTime; # apex # introduced=30 ANativeWindow_getLastQueueDuration; # apex # introduced=30 - ANativeWindow_getNextFrameId; # apex # introduced=30 ANativeWindow_getWidth; ANativeWindow_lock; ANativeWindow_query; # llndk -- cgit v1.2.3-59-g8ed1b From e4943eb672d8861d700affa2e3f3306e73a1648d Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Sat, 15 Feb 2020 18:34:59 -0800 Subject: BLASTBufferQueue: Correct deadlocks in mNextTransaction handling. There are two deadlocks in mNextTransaction handling that we adress here. The first relates to the wait-condition. Imagine we submit a buffer, now enable mNextTransaction, and queue our next buffer. In onFrameAvailable mNumAcquired will be 1 (MAX_ACQUIRED_BUFFERS), and so we will wait on the condition variable. However, we've only ever submitted one buffer, and so no callback will ever come, and we deadlock. Instead the condition should be mNumAcquired+1 meaning that we have submitted two buffers and are waiting for a callback on one of them (capturing the original intent of waiting for the callback). The second relates to the handling of mNextTransaction in transactionCallback. Imagine a scenario like this: 1. Submit a buffer, mNumAcquired = 1 2. Submit a buffer, callback for the first doesn't arrive yet, mNumAcquired = 2 3. Submit a third buffer, mNumAcquired > MAX_ACQUIRED + 1, so mAvailable = 1 and we wait for the callback. 4. Enable mNextTransaction 5. The callback arrives, but because of the !mNextTransaction condition in the callback function, we don't call processNextBuffer. We do however release one: mNumAcquired = 1, mAvailable = 1 6. At this point we queue a new buffer (The one that was just released we dequeue and queue again). But, mAvailable = 1, and so we wait on the condition variable. However the callback has already fired, and so nothing will actually process the available buffer and we wait forever. The intent of this code was to avoid using the mNextTransaction when we are processing buffers from the callback function. We capture this intent directly by using a boolean set from onFrameAvailable before calling processNextBuffer() Bug: 146598493 Bug: 149251083 Bug: 149315421 Test: Flip the flag. Play. Change-Id: I652eacf1a016f8b65fd754e47d468227bf8ecf1d --- libs/gui/BLASTBufferQueue.cpp | 12 +++++++----- libs/gui/include/gui/BLASTBufferQueue.h | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index f6493bf9c7..7a8ee8ec4c 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -174,9 +174,9 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS) { + while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { mCallbackCV.wait(_lock); } + mUseNextTransaction = true; } // add to shadow queue mNumFrameAvailable++; @@ -268,6 +269,7 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) { void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { std::lock_guard _lock{mMutex}; + mUseNextTransaction = false; mNextTransaction = t; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d72eb5a632..27d8716541 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -121,6 +121,8 @@ private: sp mBufferItemConsumer; SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex); + + bool mUseNextTransaction = false; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 0e328f6a641f256c49e2f063207eca6ddd02be60 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 6 Feb 2020 17:12:08 -0800 Subject: SurfaceControl: C++ Binding Lifetime refactoring First we eliminate the "dropReferenceTransaction" semantic. This semantic reparents the surface to null if the C++ object dies before release() is called. This is a legacy semantic from before SurfaceControls were reference counted. I point that it's unused by noting that all Java code paths will lead to calling release() in the JNI code before dropping the last reference. With dropReferenceTransaction gone we can remove mOwned it has no further uses. With these gone we now remove release() all together on the native side. This means that mClient and mHandle will only be written from the constructor and destructor making access to them thread-safe as long as you hold an sp<> to the SurfaceControl. This should prevent bugs like we've had in the past about who calls release when, no one calls it! The final question is: is removing the call to release on the Java side safe? We still need an explicit Java binding release call so we can drop the native reference in a timely fashion. This then breaks down in to two scenarios: 1. We are the last reference 2. Someone else holds a reference If we are in the first scenario, then calling release or not is equivalent to just dropping the reference. If we are in the second scenario, calling release() will be unsafe. Because we could at any time overwrite mClient/mHandle after the other ref holder had verified it was null. The main path I know of for how native code could acquire a second reference to the JNI owned SurfaceControl is via Transaction::registerSurfaceControlForCallback then if we release while Transaction::writeToParcel is running, it will inevitably segfault. This change could lead to the extension of life-time for SurfaceControl.cpp objects while the Transaction containing them is alive (but previously the SurfaceControl.cpp proxy would have been released). I also argue this is safe since the sp itself was reffed in another place in the Transaction so the lifetime of the actual server side resource isn't extended at all. Only the lightweight proxy object. Bug: 149055469 Bug: 149315421 Test: Existing tests pass. Change-Id: Ibd4d1804ef18a9c389c7f9112d15872cfe44b22e --- libs/gui/SurfaceComposerClient.cpp | 19 ++----------------- libs/gui/SurfaceControl.cpp | 17 ++--------------- libs/gui/include/gui/SurfaceComposerClient.h | 6 ------ libs/gui/include/gui/SurfaceControl.h | 7 +------ .../tests/LayerTypeAndRenderTypeTransaction_test.cpp | 3 ++- services/surfaceflinger/tests/LayerUpdate_test.cpp | 2 ++ 6 files changed, 9 insertions(+), 45 deletions(-) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7017b7c8f3..ff8b719009 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -526,21 +526,6 @@ void SurfaceComposerClient::Transaction::clear() { mDesiredPresentTime = -1; } -void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle) { - sp sf(ComposerService::getComposerService()); - Vector composerStates; - Vector displayStates; - - ComposerState s; - s.state.surface = handle; - s.state.what |= layer_state_t::eReparent; - s.state.parentHandleForChild = nullptr; - - composerStates.add(s); - sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, false, {}); -} - void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { sp sf(ComposerService::getComposerService()); @@ -1558,7 +1543,7 @@ sp SurfaceComposerClient::createWithSurfaceParent(const String8& } ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err)); if (err == NO_ERROR) { - return new SurfaceControl(this, handle, gbp, true /* owned */, transformHint); + return new SurfaceControl(this, handle, gbp, transformHint); } } return nullptr; @@ -1589,7 +1574,7 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32 } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */, transformHint); + *outSurface = new SurfaceControl(this, handle, gbp, transformHint); } } return err; diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 6292388ac3..a332a1f2a8 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -46,33 +46,21 @@ namespace android { // ============================================================================ SurfaceControl::SurfaceControl(const sp& client, const sp& handle, - const sp& gbp, bool owned, + const sp& gbp, uint32_t transform) : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), - mOwned(owned), mTransformHint(transform) {} SurfaceControl::SurfaceControl(const sp& other) { mClient = other->mClient; mHandle = other->mHandle; mGraphicBufferProducer = other->mGraphicBufferProducer; - mOwned = false; mTransformHint = other->mTransformHint; } SurfaceControl::~SurfaceControl() -{ - // Avoid reparenting the server-side surface to null if we are not the owner of it, - // meaning that we retrieved it from another process. - if (mHandle != nullptr && mOwned) { - SurfaceComposerClient::doDropReferenceTransaction(mHandle); - } - release(); -} - -void SurfaceControl::release() { // Trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. @@ -157,7 +145,6 @@ sp SurfaceControl::createSurface() const sp SurfaceControl::getHandle() const { - Mutex::Autolock lock(mLock); return mHandle; } @@ -206,7 +193,7 @@ sp SurfaceControl::readFromParcel(const Parcel* parcel) { return new SurfaceControl(new SurfaceComposerClient( interface_cast(client)), handle.get(), interface_cast(gbp), - false /* owned */, transformHint); + transformHint); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index d0bb6a39ec..27877bb174 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -183,12 +183,6 @@ public: */ static bool getProtectedContentSupport(); - /** - * Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it - * to null), but without needing an sp to avoid infinite ressurection. - */ - static void doDropReferenceTransaction(const sp& handle); - /** * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is * in order with other transactions that use buffers. diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 7bc7c686c9..ac2bbccfd2 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -58,10 +58,6 @@ public: static bool isSameSurface( const sp& lhs, const sp& rhs); - // Release the handles assosciated with the SurfaceControl, without reparenting - // them off-screen. At the moment if this isn't executed before ~SurfaceControl - // is called then the destructor will reparent the layer off-screen for you. - void release(); // Reparent off-screen and release. This is invoked by the destructor. void destroy(); @@ -89,7 +85,7 @@ public: explicit SurfaceControl(const sp& other); SurfaceControl(const sp& client, const sp& handle, - const sp& gbp, bool owned, uint32_t transformHint = 0); + const sp& gbp, uint32_t transformHint = 0); private: // can't be copied @@ -109,7 +105,6 @@ private: sp mGraphicBufferProducer; mutable Mutex mLock; mutable sp mSurfaceData; - bool mOwned; uint32_t mTransformHint; }; diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index dbace11dcb..2fd257945f 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -92,7 +92,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) { .setRelativeLayer(layerG, layerR->getHandle(), 1) .apply(); - layerG.clear(); + Transaction().reparent(layerG, nullptr).apply(); + // layerG should have been removed getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED); } diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index cf3f8e8865..cdd9d92063 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -542,6 +542,7 @@ TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) { mCapture->checkPixel(64, 64, 111, 111, 111); } + Transaction().reparent(mChild, nullptr).apply(); mChild.clear(); { @@ -1702,6 +1703,7 @@ TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); auto redLayerHandle = redLayer->getHandle(); + Transaction().reparent(redLayer, nullptr).apply(); redLayer.clear(); SurfaceComposerClient::Transaction().apply(true); -- cgit v1.2.3-59-g8ed1b From 62a4cf8c48647de3442808264005e093ab7704f0 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Fri, 31 Jan 2020 12:04:03 -0800 Subject: Add compatibility param to setFrameRate() api Add a compatiblity param to the setFrameRate() api, so the system has more info to decide the device frame rate when there are multiple competing preferences. I also changed the plumbing for setFrameRate() to go directly to surface flinger, instead of through buffer queue. We're trying to avoid changes to buffer queue code, to avoid disturbing the prebuilts. Bug: 137287430 Test: Added new cts tests to verify behavior of the compatibility param. cts-tradefed run commandAndExit cts-dev --module CtsGraphicsTestCases --test android.graphics.cts.SetFrameRateTest Test: /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter='SetFrameRateTest.*' Change-Id: Ibe75a778fb459d4138a1446c1b38b44798b56a99 --- include/android/surface_control.h | 9 ++- libs/gui/ISurfaceComposer.cpp | 66 ++++++++++++++++++++++ libs/gui/LayerState.cpp | 22 ++++++++ libs/gui/Surface.cpp | 16 ++++-- libs/gui/SurfaceComposerClient.cpp | 7 ++- libs/gui/include/gui/ISurfaceComposer.h | 7 +++ libs/gui/include/gui/LayerState.h | 15 ++++- libs/gui/include/gui/Surface.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 3 +- libs/gui/tests/Surface_test.cpp | 5 ++ libs/nativewindow/ANativeWindow.cpp | 6 +- libs/nativewindow/include/android/native_window.h | 29 +++++++++- libs/nativewindow/include/system/window.h | 6 +- libs/nativewindow/libnativewindow.map.txt | 2 +- services/surfaceflinger/BufferQueueLayer.cpp | 13 ----- services/surfaceflinger/BufferQueueLayer.h | 5 -- services/surfaceflinger/Layer.cpp | 13 +++++ services/surfaceflinger/Layer.h | 6 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 1 - services/surfaceflinger/SurfaceFlinger.cpp | 35 +++++++++++- services/surfaceflinger/SurfaceFlinger.h | 2 + .../surfaceflinger/tests/SetFrameRate_test.cpp | 14 +++-- 22 files changed, 236 insertions(+), 48 deletions(-) (limited to 'libs') diff --git a/include/android/surface_control.h b/include/android/surface_control.h index eeb8330efd..c30dcfee09 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -425,12 +425,15 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio * valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device that can * only run the display at 60fps. * + * |compatibility| The frame rate compatibility of this surface. The compatibility value may + * influence the system's choice of display frame rate. To specify a compatibility use the + * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. + * * Available since API level 30. */ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, - ASurfaceControl* surface_control, - float frameRate) - __INTRODUCED_IN(30); + ASurfaceControl* surface_control, float frameRate, + int8_t compatibility) __INTRODUCED_IN(30); #endif // __ANDROID_API__ >= 30 diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2f27fd20fd..ce41eaba1d 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1112,6 +1112,42 @@ public: } return NO_ERROR; } + + virtual status_t setFrameRate(const sp& surface, float frameRate, + int8_t compatibility) { + Parcel data, reply; + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeStrongBinder(IInterface::asBinder(surface)); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeFloat(frameRate); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err); + return err; + } + + err = data.writeByte(compatibility); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err); + return err; + } + + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply, + IBinder::FLAG_ONEWAY); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); + return err; + } + return NO_ERROR; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1877,6 +1913,36 @@ status_t BnSurfaceComposer::onTransact( return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, lightRadius); } + case SET_FRAME_RATE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp binder; + status_t err = data.readStrongBinder(&binder); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err); + return err; + } + sp surface = interface_cast(binder); + if (!surface) { + ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)", + strerror(-err), -err); + return err; + } + float frameRate; + err = data.readFloat(&frameRate); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err); + return err; + } + int8_t compatibility; + err = data.readByte(&compatibility); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); + return err; + } + status_t result = setFrameRate(surface, frameRate, compatibility); + reply->writeInt32(result); + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 5547efc3ad..a9c9b7460b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -24,6 +24,8 @@ #include #include +#include + namespace android { status_t layer_state_t::write(Parcel& output) const @@ -113,6 +115,7 @@ status_t layer_state_t::write(Parcel& output) const output.writeFloat(shadowRadius); output.writeInt32(frameRateSelectionPriority); output.writeFloat(frameRate); + output.writeByte(frameRateCompatibility); return NO_ERROR; } @@ -194,6 +197,7 @@ status_t layer_state_t::read(const Parcel& input) shadowRadius = input.readFloat(); frameRateSelectionPriority = input.readInt32(); frameRate = input.readFloat(); + frameRateCompatibility = input.readByte(); return NO_ERROR; } @@ -427,6 +431,7 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eFrameRateChanged) { what |= eFrameRateChanged; frameRate = other.frameRate; + frameRateCompatibility = other.frameRateCompatibility; } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " @@ -474,4 +479,21 @@ void InputWindowCommands::read(const Parcel& input) { syncInputWindows = input.readBool(); } +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName) { + const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; + int floatClassification = std::fpclassify(frameRate); + if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { + ALOGE("%s failed - invalid frame rate %f", functionName, frameRate); + return false; + } + + if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && + compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE) { + ALOGE("%s failed - invalid compatibility value %d", functionName, compatibility); + return false; + } + + return true; +} + }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 278cc593b7..f911e70ebf 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,6 +43,7 @@ #include #include +#include #include namespace android { @@ -1413,7 +1414,8 @@ int Surface::dispatchGetLastQueueDuration(va_list args) { int Surface::dispatchSetFrameRate(va_list args) { float frameRate = static_cast(va_arg(args, double)); - return setFrameRate(frameRate); + int8_t compatibility = static_cast(va_arg(args, int)); + return setFrameRate(frameRate, compatibility); } int Surface::dispatchAddCancelInterceptor(va_list args) { @@ -2222,11 +2224,15 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vectoronBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { ATRACE_CALL(); - ALOGV("Surface::setTargetFrameRate"); - Mutex::Autolock lock(mMutex); - return mGraphicBufferProducer->setFrameRate(frameRate); + ALOGV("Surface::setFrameRate"); + + if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) { + return BAD_VALUE; + } + + return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); } }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7017b7c8f3..7f28c6c230 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1402,14 +1402,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShado } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( - const sp& sc, float frameRate) { + const sp& sc, float frameRate, int8_t compatibility) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } + if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate")) { + mStatus = BAD_VALUE; + return *this; + } s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; + s->frameRateCompatibility = compatibility; return *this; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e860f61c22..0659f0de06 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -500,6 +500,12 @@ public: virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) = 0; + + /* + * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. + */ + virtual status_t setFrameRate(const sp& surface, float frameRate, + int8_t compatibility) = 0; }; // ---------------------------------------------------------------------------- @@ -557,6 +563,7 @@ public: SET_AUTO_LOW_LATENCY_MODE, GET_GAME_CONTENT_TYPE_SUPPORT, SET_GAME_CONTENT_TYPE, + SET_FRAME_RATE, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 2d53b48475..7e3d5d50d3 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -20,8 +20,7 @@ #include #include -#include - +#include #include #include #include @@ -36,6 +35,7 @@ #include #include #include +#include namespace android { @@ -135,7 +135,8 @@ struct layer_state_t { colorSpaceAgnostic(false), shadowRadius(0.0f), frameRateSelectionPriority(-1), - frameRate(0.0f) { + frameRate(0.0f), + frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -221,7 +222,9 @@ struct layer_state_t { // Priority of the layer assigned by Window Manager. int32_t frameRateSelectionPriority; + // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; + int8_t frameRateCompatibility; }; struct ComposerState { @@ -292,6 +295,12 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) return compare_type(lhs.token, rhs.token); } +// Returns true if the frameRate and compatibility are valid values, false +// othwerise. If either of the params are invalid, an error log is printed, and +// functionName is added to the log to indicate which function call failed. +// functionName can be null. +bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName); + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 4a353fc659..ad7cbfe914 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -179,7 +179,7 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const; // See IGraphicBufferProducer::setFrameRate - status_t setFrameRate(float frameRate); + status_t setFrameRate(float frameRate, int8_t compatibility); protected: virtual ~Surface(); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index d0bb6a39ec..fe3dec5ee5 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -525,7 +525,8 @@ public: const Rect& source, const Rect& dst, int transform); Transaction& setShadowRadius(const sp& sc, float cornerRadius); - Transaction& setFrameRate(const sp& sc, float frameRate); + Transaction& setFrameRate(const sp& sc, float frameRate, + int8_t compatibility); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 70fd888aaf..8c0f8f8de9 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -854,6 +854,11 @@ public: return NO_ERROR; } + status_t setFrameRate(const sp& /*surface*/, float /*frameRate*/, + int8_t /*compatibility*/) override { + return NO_ERROR; + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 98b76fd667..f09decf21a 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -158,11 +158,11 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { return query(window, NATIVE_WINDOW_DATASPACE); } -int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) { - if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || frameRate < 0) { +int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { return -EINVAL; } - return native_window_set_frame_rate(window, frameRate); + return native_window_set_frame_rate(window, frameRate, compatibility); } void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 4b426c518a..59aa6655b8 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -33,6 +33,7 @@ #ifndef ANDROID_NATIVE_WINDOW_H #define ANDROID_NATIVE_WINDOW_H +#include #include #include @@ -232,6 +233,24 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN #if __ANDROID_API__ >= 30 +/* Parameter for ANativeWindow_setFrameRate */ +enum { + /** + * There are no inherent restrictions on the frame rate of this window. + */ + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0, + /** + * This window is being used to display content with an inherently fixed + * frame rate, e.g. a video that has a specific frame rate. When the system + * selects a frame rate other than what the app requested, the app will need + * to do pull down or use some other technique to adapt to the system's + * frame rate. The user experience is likely to be worse (e.g. more frame + * stuttering) than it would be if the system had chosen the app's requested + * frame rate. + */ + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1 +}; + /** * Sets the intended frame rate for this window. * @@ -257,9 +276,15 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN * refresh rate for this device's display - e.g., it's fine to pass 30fps to a * device that can only run the display at 60fps. * - * \return 0 for success, -EINVAL if the window or frame rate are invalid. + * \param compatibility The frame rate compatibility of this window. The + * compatibility value may influence the system's choice of display refresh + * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. + * + * \return 0 for success, -EINVAL if the window, frame rate, or compatibility + * value are invalid. */ -int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate) __INTRODUCED_IN(30); +int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) + __INTRODUCED_IN(30); /** * Provides a hint to the window that buffers should be preallocated ahead of diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index f686147a5f..0e28fb84ca 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1015,8 +1015,10 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation); } -static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate); +static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, + int8_t compatibility) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, + (int)compatibility); } // ------------------------------------------------------------------------------------------------ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 154eb8eb52..e072e1145d 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -46,9 +46,9 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersTimestamp; # llndk ANativeWindow_setBuffersTransform; ANativeWindow_setDequeueTimeout; # apex # introduced=30 + ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk - ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setUsage; # llndk ANativeWindow_tryAllocateBuffers; # introduced=30 ANativeWindow_unlockAndPost; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index e65064bebf..f5a99cadd7 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -124,18 +124,6 @@ bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { return isDue || !isPlausible; } -bool BufferQueueLayer::setFrameRate(FrameRate frameRate) { - float oldFrameRate = 0.f; - status_t result = mConsumer->getFrameRate(&oldFrameRate); - bool frameRateChanged = result < 0 || frameRate.rate != oldFrameRate; - mConsumer->setFrameRate(frameRate.rate); - return frameRateChanged; -} - -Layer::FrameRate BufferQueueLayer::getFrameRate() const { - return FrameRate(mLatchedFrameRate, Layer::FrameRateCompatibility::Default); -} - // ----------------------------------------------------------------------- // Interface implementation for BufferLayer // ----------------------------------------------------------------------- @@ -578,7 +566,6 @@ void BufferQueueLayer::gatherBufferInfo() { mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse(); float latchedFrameRate; mConsumer->getFrameRate(&latchedFrameRate); - mLatchedFrameRate = latchedFrameRate; } sp BufferQueueLayer::createClone() { diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 626af4b6f1..5f7587c547 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -56,9 +56,6 @@ public: bool shouldPresentNow(nsecs_t expectedPresentTime) const override; - bool setFrameRate(FrameRate frameRate) override; - FrameRate getFrameRate() const override; - // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- @@ -155,8 +152,6 @@ private: std::atomic mSidebandStreamChanged{false}; sp mContentsChangedListener; - - std::atomic mLatchedFrameRate = 0.f; }; } // namespace android diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index da26a374db..d7647d76d3 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -26,6 +26,7 @@ #include "Layer.h" #include +#include #include #include #include @@ -2446,6 +2447,18 @@ void Layer::addChildToDrawing(const sp& layer) { layer->mDrawingParent = this; } +Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) { + switch (compatibility) { + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT: + return FrameRateCompatibility::Default; + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE: + return FrameRateCompatibility::ExactOrMultiple; + default: + LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); + return FrameRateCompatibility::Default; + } +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 37ae340653..5d2144aed4 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -161,6 +161,10 @@ public: } bool operator!=(const FrameRate& other) const { return !(*this == other); } + + // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a + // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. + static FrameRateCompatibility convertCompatibility(int8_t compatibility); }; struct State { @@ -795,7 +799,7 @@ public: */ Rect getCroppedBufferSize(const Layer::State& s) const; - virtual bool setFrameRate(FrameRate frameRate); + bool setFrameRate(FrameRate frameRate); virtual FrameRate getFrameRate() const; protected: diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index b313777253..b851fc6ebb 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -179,4 +179,3 @@ void LayerHistory::clear() { mActiveLayersEnd = 0; } } // namespace android::scheduler::impl - diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a98ff4fe7c..2701c3e6c9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -34,6 +34,8 @@ #include #include +#include + #include #include @@ -58,6 +60,7 @@ #include #include #include +#include #include #include not need to + * be a valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device + * that can only run the display at 60fps. * * |compatibility| The frame rate compatibility of this surface. The compatibility value may * influence the system's choice of display frame rate. To specify a compatibility use the diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 59aa6655b8..25130e2a03 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -233,15 +233,15 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN #if __ANDROID_API__ >= 30 -/* Parameter for ANativeWindow_setFrameRate */ -enum { +/** Compatibility value for ANativeWindow_setFrameRate. */ +enum ANativeWindow_FrameRateCompatibility { /** * There are no inherent restrictions on the frame rate of this window. */ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0, /** * This window is being used to display content with an inherently fixed - * frame rate, e.g. a video that has a specific frame rate. When the system + * frame rate, e.g.\ a video that has a specific frame rate. When the system * selects a frame rate other than what the app requested, the app will need * to do pull down or use some other technique to adapt to the system's * frame rate. The user experience is likely to be worse (e.g. more frame @@ -272,9 +272,9 @@ enum { * \param frameRate The intended frame rate of this window, in frames per * second. 0 is a special value that indicates the app will accept the system's * choice for the display frame rate, which is the default behavior if this - * function isn't called. The frameRate param does *not* need to be a valid - * refresh rate for this device's display - e.g., it's fine to pass 30fps to a - * device that can only run the display at 60fps. + * function isn't called. The frameRate param does not need to be a + * valid refresh rate for this device's display - e.g., it's fine to pass 30fps + * to a device that can only run the display at 60fps. * * \param compatibility The frame rate compatibility of this window. The * compatibility value may influence the system's choice of display refresh -- cgit v1.2.3-59-g8ed1b From 0cffd2ce4704e636564d8352ccdc04a4e1e3f05a Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Tue, 24 Mar 2020 10:23:09 -0700 Subject: Add new appops to native APIs The bug was that native code started to use an op-code that was higher than _NUM_OP which lead to array-out-of-bound exceptions. Fixes: 152229280 Test: TH Change-Id: I8831f0d161c770fcbab557934e0717b49dc1bd80 Exempt-From-Owner-Approval: Was +2'ed. I had to resolve merge conflict. --- libs/binder/include/binder/AppOpsManager.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index 2ee5930f2b..6afcd77e70 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -122,7 +122,16 @@ public: OP_LEGACY_STORAGE = 87, OP_ACCESS_ACCESSIBILITY = 88, OP_READ_DEVICE_IDENTIFIERS = 89, - _NUM_OP = 90 + OP_ACCESS_MEDIA_LOCATION = 90, + OP_QUERY_ALL_PACKAGES = 91, + OP_MANAGE_EXTERNAL_STORAGE = 92, + OP_INTERACT_ACROSS_PROFILES = 93, + OP_ACTIVATE_PLATFORM_VPN = 94, + OP_LOADER_USAGE_STATS = 95, + OP_DEPRECATED_1 = 96, + OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97, + OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98, + _NUM_OP = 99 }; AppOpsManager(); -- cgit v1.2.3-59-g8ed1b From 8f54d11c657aadb35a1892db73943cdfa9c6edd3 Mon Sep 17 00:00:00 2001 From: Hayden Gomes Date: Thu, 26 Mar 2020 14:23:33 -0700 Subject: Adding audiocontrol@2.0 to hal interfaces to dump Bug: 148098383 Test: adb bugreport | grep audiocontrol Change-Id: I28610c75cdc8699f884dd9f330776bd477458229 Merged-In: I28610c75cdc8699f884dd9f330776bd477458229 (cherry picked from commit b11a1b792f130389d55cb11a5a3e0089882d49b8) --- libs/dumputils/dump_utils.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index fa1b2b74ae..2e144084c1 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -57,6 +57,7 @@ static const char* hal_interfaces_to_dump[] { "android.hardware.audio@5.0::IDevicesFactory", "android.hardware.audio@6.0::IDevicesFactory", "android.hardware.automotive.audiocontrol@1.0::IAudioControl", + "android.hardware.automotive.audiocontrol@2.0::IAudioControl", "android.hardware.automotive.evs@1.0::IEvsCamera", "android.hardware.automotive.vehicle@2.0::IVehicle", "android.hardware.biometrics.face@1.0::IBiometricsFace", -- cgit v1.2.3-59-g8ed1b From 5b2ae91025bed064887c7178b1aa0a19c50caaed Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 1 Apr 2020 15:40:40 -0700 Subject: BLASTBufferQueue: Pass same default usage as BufferQueueLayer The default usage value for BufferQueueLayer is COMPOSER not FRAMEBUFFER (see Layer::getEffectiveUsage). It's unclear exactly what effect this was having. Bug: 152501005 Test: Existing tests pass. Change-Id: I33adc9c39c57b11c71a53e936448c9052bd83155 --- libs/gui/BLASTBufferQueue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 30e1351b33..545ae5b04e 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -110,7 +110,7 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, mProducer->setMaxDequeuedBufferCount(2); } mBufferItemConsumer = - new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true); + new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, true); static int32_t id = 0; auto name = std::string("BLAST Consumer") + std::to_string(id); id++; -- cgit v1.2.3-59-g8ed1b From 9f133d7700b16b01070177f5e10750c8e8cf50fe Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 1 Apr 2020 15:51:46 -0700 Subject: BLASTBufferQueue: Initialize transform hint on creation. BufferQueueLayer does it (see onFirstRef) so we probably should too. In particular it could be important to set it before buffer allocation. Bug: 152501005 Test: Existing tests pass Change-Id: I60edd273dabb1f5b2176f55b6bd7cf92c0557ae1 --- libs/gui/BLASTBufferQueue.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 545ae5b04e..c73d92cd9c 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -119,7 +119,9 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, mBufferItemConsumer->setBufferFreedListener(this); mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888); + mTransformHint = mSurfaceControl->getTransformHint(); + mBufferItemConsumer->setTransformHint(mTransformHint); mNumAcquired = 0; mNumFrameAvailable = 0; -- cgit v1.2.3-59-g8ed1b From fc4165121b6343e674f3899784eeef367f3801fa Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 2 Apr 2020 12:32:44 -0700 Subject: BLASTBufferQueue: Avoid duplicate calls to setDefaultBufferSize Calling in to the consumer may acquire the BufferQueueCore mutex. We call BLASTBufferQueue::update from the UI thread. And so we can accidentally end up blocking the UI thread on allocateBuffers() during app start-up. Bug: 152501005 Test: Flip BLAST. Play. Change-Id: I89034211ed5725b5be6391cc2bac748c0acf1eb3 --- libs/gui/BLASTBufferQueue.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index c73d92cd9c..a8384accce 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -132,9 +132,12 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, void BLASTBufferQueue::update(const sp& surface, int width, int height) { std::unique_lock _lock{mMutex}; mSurfaceControl = surface; - mWidth = width; - mHeight = height; - mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); + + if (mWidth != width || mHeight != height) { + mWidth = width; + mHeight = height; + mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight); + } } static void transactionCallbackThunk(void* context, nsecs_t latchTime, -- cgit v1.2.3-59-g8ed1b From 28b9fa26f16b8d788d749c47d30ed3e450bff92b Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 2 Apr 2020 15:29:35 -0700 Subject: Reallocate blur textures if they don't fit RenderEngine#drawLayers might be called with multiple display sizes. Sometimes, the display might be quite small, not reflecting a physical device. This happens becuse we support color sampling, and in those cases we can render only a small portion of the output. This could lead to FBO allocation that doesn't represent the surface that we'll render to. To fix the issue, the textures need to be resized when necessary. Test: manual Fixes: 152282559 Change-Id: I80d0c741b7f701a64fb862273433b167a97fe0bb --- libs/renderengine/gl/filters/BlurFilter.cpp | 6 ++++-- libs/renderengine/gl/filters/BlurFilter.h | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index 6ba78dc025..59469d43d8 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -69,7 +69,10 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra ATRACE_NAME("BlurFilter::setAsDrawTarget"); mRadius = radius; - if (!mTexturesAllocated) { + if (mDisplayWidth < display.physicalDisplay.width() || + mDisplayHeight < display.physicalDisplay.height()) { + ATRACE_NAME("BlurFilter::allocatingTextures"); + mDisplayWidth = display.physicalDisplay.width(); mDisplayHeight = display.physicalDisplay.height(); mCompositionFbo.allocateBuffers(mDisplayWidth, mDisplayHeight); @@ -78,7 +81,6 @@ status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t ra const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale); mPingFbo.allocateBuffers(fboWidth, fboHeight); mPongFbo.allocateBuffers(fboWidth, fboHeight); - mTexturesAllocated = true; if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { ALOGE("Invalid ping buffer"); diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 3eb5c96664..36e5a7730b 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -67,11 +67,10 @@ private: // Frame buffers holding the blur passes. GLFramebuffer mPingFbo; GLFramebuffer mPongFbo; - uint32_t mDisplayWidth; - uint32_t mDisplayHeight; + uint32_t mDisplayWidth = 0; + uint32_t mDisplayHeight = 0; // Buffer holding the final blur pass. GLFramebuffer* mLastDrawTarget; - bool mTexturesAllocated = false; // VBO containing vertex and uv data of a fullscreen triangle. GLVertexBuffer mMeshBuffer; -- cgit v1.2.3-59-g8ed1b From fe76013f339325b68f00f3ce4491cf0f1ef3f7e7 Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Fri, 3 Apr 2020 00:38:46 -0700 Subject: Making native transactions one-way as well. Fixing crash in native callback after changing permissions. Bug: b/152633648 Test: adb shell appops set 1000 GET_USAGE_STATS deny Change-Id: Ifbc2d2d982d2dd9b0b9c0ed109f827de9bed2768 --- libs/binder/IAppOpsCallback.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp index 0ce1dd59cf..b9eb281870 100644 --- a/libs/binder/IAppOpsCallback.cpp +++ b/libs/binder/IAppOpsCallback.cpp @@ -39,7 +39,7 @@ public: data.writeInterfaceToken(IAppOpsCallback::getInterfaceDescriptor()); data.writeInt32(op); data.writeString16(packageName); - remote()->transact(OP_CHANGED_TRANSACTION, data, &reply); + remote()->transact(OP_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY); } }; @@ -58,7 +58,6 @@ status_t BnAppOpsCallback::onTransact( String16 packageName; (void)data.readString16(&packageName); opChanged(op, packageName); - reply->writeNoException(); return NO_ERROR; } break; default: -- cgit v1.2.3-59-g8ed1b From 571aa9c1d94f3de4bb55e03d26bcad962f03114d Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 2 Apr 2020 11:43:21 -0700 Subject: Performance optimizations - Perform blur operation while downsampling to save 1 pass - Remove unnecessary glBindFrameBuffer calls, given that they might flush the gl pipeline. Bug: 152792193 Test: systraces Change-Id: I462de2642c0400dd31d1808fdfcf522c319fa839 --- libs/renderengine/gl/filters/BlurFilter.cpp | 44 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index 6ba78dc025..eca1ac5a4a 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -54,13 +54,13 @@ BlurFilter::BlurFilter(GLESRenderEngine& engine) static constexpr auto translation = 1.0f; const GLfloat vboData[] = { // Vertex data - translation-size, -translation-size, - translation-size, -translation+size, - translation+size, -translation+size, + translation - size, -translation - size, + translation - size, -translation + size, + translation + size, -translation + size, // UV data - 0.0f, 0.0f-translation, - 0.0f, size-translation, - size, size-translation + 0.0f, 0.0f - translation, + 0.0f, size - translation, + size, size - translation }; mMeshBuffer.allocateBuffers(vboData, 12 /* size */); } @@ -120,27 +120,35 @@ void BlurFilter::drawMesh(GLuint uv, GLuint position) { status_t BlurFilter::prepare() { ATRACE_NAME("BlurFilter::prepare"); - blit(mCompositionFbo, mPingFbo); // Kawase is an approximation of Gaussian, but it behaves differently from it. // A radius transformation is required for approximating them, and also to introduce // non-integer steps, necessary to smoothly interpolate large radii. - auto radius = mRadius / 6.0f; + const auto radius = mRadius / 6.0f; // Calculate how many passes we'll do, based on the radius. // Too many passes will make the operation expensive. - auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); + const auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); - // We'll ping pong between our textures, to accumulate the result of various offsets. + const float radiusByPasses = radius / (float)passes; + const float stepX = radiusByPasses / (float)mCompositionFbo.getBufferWidth(); + const float stepY = radiusByPasses / (float)mCompositionFbo.getBufferHeight(); + + // Let's start by downsampling and blurring the composited frame simultaneously. mBlurProgram.useProgram(); + glActiveTexture(GL_TEXTURE0); + glUniform1i(mBTextureLoc, 0); + glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); + glUniform2f(mBOffsetLoc, stepX, stepY); + glViewport(0, 0, mPingFbo.getBufferWidth(), mPingFbo.getBufferHeight()); + mPingFbo.bind(); + drawMesh(mBUvLoc, mBPosLoc); + + // And now we'll ping pong between our textures, to accumulate the result of various offsets. GLFramebuffer* read = &mPingFbo; GLFramebuffer* draw = &mPongFbo; - float stepX = radius / (float)mCompositionFbo.getBufferWidth() / (float)passes; - float stepY = radius / (float)mCompositionFbo.getBufferHeight() / (float)passes; glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); - glActiveTexture(GL_TEXTURE0); - glUniform1i(mBTextureLoc, 0); - for (auto i = 0; i < passes; i++) { + for (auto i = 1; i < passes; i++) { ATRACE_NAME("BlurFilter::renderPass"); draw->bind(); @@ -156,9 +164,6 @@ status_t BlurFilter::prepare() { } mLastDrawTarget = read; - // Cleanup - glBindFramebuffer(GL_FRAMEBUFFER, 0); - return NO_ERROR; } @@ -177,7 +182,6 @@ status_t BlurFilter::render(bool multiPass) { glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(), mLastDrawTarget->getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); return NO_ERROR; } @@ -256,12 +260,12 @@ string BlurFilter::getMixFragShader() const { } void BlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const { + ATRACE_NAME("BlurFilter::blit"); read.bindAsReadBuffer(); draw.bindAsDrawBuffer(); glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0, draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT, GL_LINEAR); - glBindFramebuffer(GL_FRAMEBUFFER, 0); } } // namespace gl -- cgit v1.2.3-59-g8ed1b From d407190b3691b8b404143281840b805ee21d7f8f Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Tue, 24 Mar 2020 16:02:53 -0700 Subject: Add frame rate flexibility token Add support for temporarily relaxing frame rate restrictions in surface flinger. This is used by CTS tests to get a consistent device state while running frame rate tests. Bug: 148033900 Test: - On a Pixel 4, I turned the brightness down and covered the ambient light sensor, causing the display manager to set a frame rate restriction. I ran the frame rate CTS test without these CLs applied, and confirmed the test failed because surface flinger couldn't switch frame rates, as expected. Then I ran the tests with the CLs applied, and confirmed the tests pass. - I confirmed that, without adopting shell permission identity, the CTS test is denied the request to acquire a frame rate flexibility token. So normal apps won't be able to access this. Change-Id: I6685edc4bc07c7888b79a9dd72a90f56b74e7604 --- libs/gui/ISurfaceComposer.cpp | 46 ++++++ libs/gui/include/gui/ISurfaceComposer.h | 9 ++ libs/gui/tests/Surface_test.cpp | 2 + .../Scheduler/RefreshRateConfigs.cpp | 86 ++++++++---- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 65 ++++++--- services/surfaceflinger/SurfaceFlinger.cpp | 155 ++++++++++++++++----- services/surfaceflinger/SurfaceFlinger.h | 14 +- .../tests/unittests/RefreshRateConfigsTest.cpp | 49 +++++-- 8 files changed, 334 insertions(+), 92 deletions(-) (limited to 'libs') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8d79cf8723..bd4d62c4f7 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1145,6 +1145,42 @@ public: ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); return err; } + + return reply.readInt32(); + } + + virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) { + if (!outToken) return BAD_VALUE; + + Parcel data, reply; + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: failed writing interface token: %s (%d)", + strerror(-err), -err); + return err; + } + + err = remote()->transact(BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, data, + &reply); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: failed to transact: %s (%d)", strerror(-err), + err); + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: call failed: %s (%d)", strerror(-err), err); + return err; + } + + err = reply.readStrongBinder(outToken); + if (err != NO_ERROR) { + ALOGE("acquireFrameRateFlexibilityToken: failed reading binder token: %s (%d)", + strerror(-err), err); + return err; + } + return NO_ERROR; } }; @@ -1945,6 +1981,16 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp token; + status_t result = acquireFrameRateFlexibilityToken(&token); + reply->writeInt32(result); + if (result == NO_ERROR) { + reply->writeStrongBinder(token); + } + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 09487eab8b..3cef25639f 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -508,6 +508,14 @@ public: */ virtual status_t setFrameRate(const sp& surface, float frameRate, int8_t compatibility) = 0; + + /* + * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, + * surface flinger will freely switch between frame rates in any way it sees fit, regardless of + * the current restrictions applied by DisplayManager. This is useful to get consistent behavior + * for tests. Release the token by releasing the returned IBinder reference. + */ + virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) = 0; }; // ---------------------------------------------------------------------------- @@ -566,6 +574,7 @@ public: GET_GAME_CONTENT_TYPE_SUPPORT, SET_GAME_CONTENT_TYPE, SET_FRAME_RATE, + ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, // Always append new enum to the end. }; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 8c0f8f8de9..ef1fd026f2 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -859,6 +859,8 @@ public: return NO_ERROR; } + status_t acquireFrameRateFlexibilityToken(sp* /*outToken*/) { return NO_ERROR; } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 02d0b5359c..14ef73335e 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -301,7 +301,7 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() con mCurrentRefreshRate) != mAvailableRefreshRates.end()) { return *mCurrentRefreshRate; } - return *mRefreshRates.at(mDefaultConfig); + return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig); } void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) { @@ -326,38 +326,59 @@ RefreshRateConfigs::RefreshRateConfigs( init(inputConfigs, currentConfigId); } -status_t RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate, - float maxRefreshRate, bool* outPolicyChanged) { - std::lock_guard lock(mLock); - bool policyChanged = defaultConfigId != mDefaultConfig || - minRefreshRate != mMinRefreshRateFps || maxRefreshRate != mMaxRefreshRateFps; - if (outPolicyChanged) { - *outPolicyChanged = policyChanged; +bool RefreshRateConfigs::isPolicyValid(const Policy& policy) { + // defaultConfig must be a valid config, and within the given refresh rate range. + auto iter = mRefreshRates.find(policy.defaultConfig); + if (iter == mRefreshRates.end()) { + return false; } - if (!policyChanged) { - return NO_ERROR; + const RefreshRate& refreshRate = *iter->second; + if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) { + return false; } - // defaultConfigId must be a valid config ID, and within the given refresh rate range. - if (mRefreshRates.count(defaultConfigId) == 0) { + return true; +} + +status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { + std::lock_guard lock(mLock); + if (!isPolicyValid(policy)) { return BAD_VALUE; } - const RefreshRate& refreshRate = *mRefreshRates.at(defaultConfigId); - if (!refreshRate.inPolicy(minRefreshRate, maxRefreshRate)) { + Policy previousPolicy = *getCurrentPolicyLocked(); + mDisplayManagerPolicy = policy; + if (*getCurrentPolicyLocked() == previousPolicy) { + return CURRENT_POLICY_UNCHANGED; + } + constructAvailableRefreshRates(); + return NO_ERROR; +} + +status_t RefreshRateConfigs::setOverridePolicy(const std::optional& policy) { + std::lock_guard lock(mLock); + if (policy && !isPolicyValid(*policy)) { return BAD_VALUE; } - mDefaultConfig = defaultConfigId; - mMinRefreshRateFps = minRefreshRate; - mMaxRefreshRateFps = maxRefreshRate; + Policy previousPolicy = *getCurrentPolicyLocked(); + mOverridePolicy = policy; + if (*getCurrentPolicyLocked() == previousPolicy) { + return CURRENT_POLICY_UNCHANGED; + } constructAvailableRefreshRates(); return NO_ERROR; } -void RefreshRateConfigs::getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate, - float* maxRefreshRate) const { +const RefreshRateConfigs::Policy* RefreshRateConfigs::getCurrentPolicyLocked() const { + return mOverridePolicy ? &mOverridePolicy.value() : &mDisplayManagerPolicy; +} + +RefreshRateConfigs::Policy RefreshRateConfigs::getCurrentPolicy() const { + std::lock_guard lock(mLock); + return *getCurrentPolicyLocked(); +} + +RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const { std::lock_guard lock(mLock); - *defaultConfigId = mDefaultConfig; - *minRefreshRate = mMinRefreshRateFps; - *maxRefreshRate = mMaxRefreshRateFps; + return mDisplayManagerPolicy; } bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const { @@ -385,19 +406,25 @@ void RefreshRateConfigs::getSortedRefreshRateList( std::sort(outRefreshRates->begin(), outRefreshRates->end(), [](const auto refreshRate1, const auto refreshRate2) { - return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + if (refreshRate1->vsyncPeriod != refreshRate2->vsyncPeriod) { + return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + } else { + return refreshRate1->configGroup > refreshRate2->configGroup; + } }); } void RefreshRateConfigs::constructAvailableRefreshRates() { // Filter configs based on current policy and sort based on vsync period - HwcConfigGroupType group = mRefreshRates.at(mDefaultConfig)->configGroup; + const Policy* policy = getCurrentPolicyLocked(); + HwcConfigGroupType group = mRefreshRates.at(policy->defaultConfig)->configGroup; ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f", - mDefaultConfig.value(), group.value(), mMinRefreshRateFps, mMaxRefreshRateFps); + policy->defaultConfig.value(), group.value(), policy->minRefreshRate, + policy->maxRefreshRate); getSortedRefreshRateList( [&](const RefreshRate& refreshRate) REQUIRES(mLock) { - return refreshRate.configGroup == group && - refreshRate.inPolicy(mMinRefreshRateFps, mMaxRefreshRateFps); + return (policy->allowGroupSwitching || refreshRate.configGroup == group) && + refreshRate.inPolicy(policy->minRefreshRate, policy->maxRefreshRate); }, &mAvailableRefreshRates); @@ -409,7 +436,8 @@ void RefreshRateConfigs::constructAvailableRefreshRates() { ALOGV("Available refresh rates: %s", availableRefreshRates.c_str()); LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(), "No compatible display configs for default=%d min=%.0f max=%.0f", - mDefaultConfig.value(), mMinRefreshRateFps, mMaxRefreshRateFps); + policy->defaultConfig.value(), policy->minRefreshRate, + policy->maxRefreshRate); } // NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor @@ -432,7 +460,7 @@ void RefreshRateConfigs::init(const std::vector& configs, std::vector sortedConfigs; getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs); - mDefaultConfig = currentHwcConfig; + mDisplayManagerPolicy.defaultConfig = currentHwcConfig; mMinSupportedRefreshRate = sortedConfigs.front(); mMaxSupportedRefreshRate = sortedConfigs.back(); constructAvailableRefreshRates(); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 87d43898d9..e749f8fb93 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -20,6 +20,7 @@ #include #include +#include #include #include "DisplayHardware/HWComposer.h" @@ -90,14 +91,47 @@ public: using AllRefreshRatesMapType = std::unordered_map>; - // Sets the current policy to choose refresh rates. Returns NO_ERROR if the requested policy is - // valid, or a negative error value otherwise. policyChanged, if non-null, will be set to true - // if the new policy is different from the old policy. - status_t setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate, - float maxRefreshRate, bool* policyChanged) EXCLUDES(mLock); - // Gets the current policy. - void getPolicy(HwcConfigIndexType* defaultConfigId, float* minRefreshRate, - float* maxRefreshRate) const EXCLUDES(mLock); + struct Policy { + // The default config, used to ensure we only initiate display config switches within the + // same config group as defaultConfigId's group. + HwcConfigIndexType defaultConfig; + // The min and max FPS allowed by the policy. + float minRefreshRate = 0; + float maxRefreshRate = std::numeric_limits::max(); + // Whether or not we switch config groups to get the best frame rate. Only used by tests. + bool allowGroupSwitching = false; + + bool operator==(const Policy& other) const { + return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate && + maxRefreshRate == other.maxRefreshRate && + allowGroupSwitching == other.allowGroupSwitching; + } + + bool operator!=(const Policy& other) const { return !(*this == other); } + }; + + // Return code set*Policy() to indicate the current policy is unchanged. + static constexpr int CURRENT_POLICY_UNCHANGED = 1; + + // We maintain the display manager policy and the override policy separately. The override + // policy is used by CTS tests to get a consistent device state for testing. While the override + // policy is set, it takes precedence over the display manager policy. Once the override policy + // is cleared, we revert to using the display manager policy. + + // Sets the display manager policy to choose refresh rates. The return value will be: + // - A negative value if the policy is invalid or another error occurred. + // - NO_ERROR if the policy was successfully updated, and the current policy is different from + // what it was before the call. + // - CURRENT_POLICY_UNCHANGED if the policy was successfully updated, but the current policy + // is the same as it was before the call. + status_t setDisplayManagerPolicy(const Policy& policy) EXCLUDES(mLock); + // Sets the override policy. See setDisplayManagerPolicy() for the meaning of the return value. + status_t setOverridePolicy(const std::optional& policy) EXCLUDES(mLock); + // Gets the current policy, which will be the override policy if active, and the display manager + // policy otherwise. + Policy getCurrentPolicy() const EXCLUDES(mLock); + // Gets the display manager policy, regardless of whether an override policy is active. + Policy getDisplayManagerPolicy() const EXCLUDES(mLock); // Returns true if config is allowed by the current policy. bool isConfigAllowed(HwcConfigIndexType config) const EXCLUDES(mLock); @@ -208,6 +242,9 @@ private: // the policy. const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock); + const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); + bool isPolicyValid(const Policy& policy); + // The list of refresh rates, indexed by display config ID. This must not change after this // object is initialized. AllRefreshRatesMapType mRefreshRates; @@ -220,14 +257,10 @@ private: // the main thread, and read by the Scheduler (and other objects) on other threads. const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock); - // The default config. This will change at runtime. This is set by SurfaceFlinger on - // the main thread, and read by the Scheduler (and other objects) on other threads. - HwcConfigIndexType mDefaultConfig GUARDED_BY(mLock); - - // The min and max FPS allowed by the policy. This will change at runtime and set by - // SurfaceFlinger on the main thread. - float mMinRefreshRateFps GUARDED_BY(mLock) = 0; - float mMaxRefreshRateFps GUARDED_BY(mLock) = std::numeric_limits::max(); + // The policy values will change at runtime. They're set by SurfaceFlinger on the main thread, + // and read by the Scheduler (and other objects) on other threads. + Policy mDisplayManagerPolicy GUARDED_BY(mLock); + std::optional mOverridePolicy GUARDED_BY(mLock); // The min and max refresh rates supported by the device. // This will not change at runtime. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dd2be7c431..c47bf94a12 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -200,6 +200,15 @@ bool validateCompositionDataspace(Dataspace dataspace) { return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3; } +class FrameRateFlexibilityToken : public BBinder { +public: + FrameRateFlexibilityToken(std::function callback) : mCallback(callback) {} + virtual ~FrameRateFlexibilityToken() { mCallback(); } + +private: + std::function mCallback; +}; + } // namespace anonymous // --------------------------------------------------------------------------- @@ -977,8 +986,11 @@ status_t SurfaceFlinger::setActiveConfig(const sp& displayToken, int mo } else { HwcConfigIndexType config(mode); const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(config); - result = setDesiredDisplayConfigSpecsInternal(display, config, refreshRate.fps, - refreshRate.fps); + result = setDesiredDisplayConfigSpecsInternal(display, + scheduler::RefreshRateConfigs:: + Policy{config, refreshRate.fps, + refreshRate.fps}, + /*overridePolicy=*/false); } })); @@ -3496,12 +3508,13 @@ uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) { return flags; } -bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess() { +bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache) { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && - !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { + (usePermissionCache ? !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid) + : !checkPermission(sAccessSurfaceFlinger, pid, uid))) { return false; } return true; @@ -4373,13 +4386,11 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", dispSyncPresentTimeOffset, getVsyncPeriod()); - HwcConfigIndexType defaultConfig; - float minFps, maxFps; - mRefreshRateConfigs->getPolicy(&defaultConfig, &minFps, &maxFps); + scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); StringAppendF(&result, "DesiredDisplayConfigSpecs: default config ID: %d" ", min: %.2f Hz, max: %.2f Hz", - defaultConfig.value(), minFps, maxFps); + policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate); StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); @@ -4818,8 +4829,12 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: case GET_DISPLAYED_CONTENT_SAMPLE: case NOTIFY_POWER_HINT: - case SET_GLOBAL_SHADOW_SETTINGS: { - if (!callingThreadHasUnscopedSurfaceFlingerAccess()) { + case SET_GLOBAL_SHADOW_SETTINGS: + case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { + // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN is used by CTS tests, which acquire the + // necessary permission dynamically. Don't use the permission cache for this check. + bool usePermissionCache = code != ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN; + if (!callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", ipc->getCallingPid(), ipc->getCallingUid()); @@ -5908,12 +5923,15 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp& disp } } -status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const sp& display, - HwcConfigIndexType defaultConfig, - float minRefreshRate, - float maxRefreshRate) { +status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( + const sp& display, + const std::optional& policy, bool overridePolicy) { Mutex::Autolock lock(mStateLock); + LOG_ALWAYS_FATAL_IF(!display->isPrimary() && overridePolicy, + "Can only set override policy on the primary display"); + LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy"); + if (!display->isPrimary()) { // TODO(b/144711714): For non-primary displays we should be able to set an active config // as well. For now, just call directly to setActiveConfigWithConstraints but ideally @@ -5927,7 +5945,8 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const spdefaultConfig.value(), constraints, &timeline) < 0) { return BAD_VALUE; } @@ -5935,11 +5954,12 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const spsetActiveConfig(defaultConfig); - const nsecs_t vsyncPeriod = - getHwComposer().getConfigs(*displayId)[defaultConfig.value()]->getVsyncPeriod(); - mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, defaultConfig, - vsyncPeriod); + display->setActiveConfig(policy->defaultConfig); + const nsecs_t vsyncPeriod = getHwComposer() + .getConfigs(*displayId)[policy->defaultConfig.value()] + ->getVsyncPeriod(); + mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, + policy->defaultConfig, vsyncPeriod); return NO_ERROR; } @@ -5948,17 +5968,20 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const spsetPolicy(defaultConfig, minRefreshRate, maxRefreshRate, - &policyChanged) < 0) { + status_t setPolicyResult = overridePolicy + ? mRefreshRateConfigs->setOverridePolicy(policy) + : mRefreshRateConfigs->setDisplayManagerPolicy(*policy); + if (setPolicyResult < 0) { return BAD_VALUE; } - if (!policyChanged) { + if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) { return NO_ERROR; } + scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f", - defaultConfig.value(), minRefreshRate, maxRefreshRate); + currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate, + currentPolicy.maxRefreshRate); // TODO(b/140204874): This hack triggers a notification that something has changed, so // that listeners that care about a change in allowed configs can get the notification. @@ -5972,7 +5995,7 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(const spgetRefreshRateFromConfigId(*configId) // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind. - : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig); + : mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig); ALOGV("trying to switch to Scheduler preferred config %d (%s)", preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str()); @@ -6007,9 +6030,13 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp& display result = BAD_VALUE; ALOGW("Attempt to set desired display configs for virtual display"); } else { - result = - setDesiredDisplayConfigSpecsInternal(display, HwcConfigIndexType(defaultConfig), - minRefreshRate, maxRefreshRate); + result = setDesiredDisplayConfigSpecsInternal(display, + scheduler::RefreshRateConfigs:: + Policy{HwcConfigIndexType( + defaultConfig), + minRefreshRate, + maxRefreshRate}, + /*overridePolicy=*/false); } })); @@ -6033,9 +6060,11 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp& display } if (display->isPrimary()) { - HwcConfigIndexType defaultConfig; - mRefreshRateConfigs->getPolicy(&defaultConfig, outMinRefreshRate, outMaxRefreshRate); - *outDefaultConfig = defaultConfig.value(); + scheduler::RefreshRateConfigs::Policy policy = + mRefreshRateConfigs->getDisplayManagerPolicy(); + *outDefaultConfig = policy.defaultConfig.value(); + *outMinRefreshRate = policy.minRefreshRate; + *outMaxRefreshRate = policy.maxRefreshRate; return NO_ERROR; } else if (display->isVirtual()) { return BAD_VALUE; @@ -6155,6 +6184,68 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, return NO_ERROR; } +status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp* outToken) { + if (!outToken) { + return BAD_VALUE; + } + status_t result = NO_ERROR; + postMessageSync(new LambdaMessage([&]() { + if (mFrameRateFlexibilityTokenCount == 0) { + // |mStateLock| not needed as we are on the main thread + const auto display = getDefaultDisplayDeviceLocked(); + + // This is a little racy, but not in a way that hurts anything. As we grab the + // defaultConfig from the display manager policy, we could be setting a new display + // manager policy, leaving us using a stale defaultConfig. The defaultConfig doesn't + // matter for the override policy though, since we set allowGroupSwitching to true, so + // it's not a problem. + scheduler::RefreshRateConfigs::Policy overridePolicy; + overridePolicy.defaultConfig = + mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig; + overridePolicy.allowGroupSwitching = true; + result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy, + /*overridePolicy=*/true); + } + + if (result == NO_ERROR) { + mFrameRateFlexibilityTokenCount++; + // Handing out a reference to the SurfaceFlinger object, as we're doing in the line + // below, is something to consider carefully. The lifetime of the + // FrameRateFlexibilityToken isn't tied to SurfaceFlinger object lifetime, so if this + // SurfaceFlinger object were to be destroyed while the token still exists, the token + // destructor would be accessing a stale SurfaceFlinger reference, and crash. This is ok + // in this case, for two reasons: + // 1. Once SurfaceFlinger::run() is called by main_surfaceflinger.cpp, the only way + // the program exits is via a crash. So we won't have a situation where the + // SurfaceFlinger object is dead but the process is still up. + // 2. The frame rate flexibility token is acquired/released only by CTS tests, so even + // if condition 1 were changed, the problem would only show up when running CTS tests, + // not on end user devices, so we could spot it and fix it without serious impact. + *outToken = new FrameRateFlexibilityToken( + [this]() { onFrameRateFlexibilityTokenReleased(); }); + ALOGD("Frame rate flexibility token acquired. count=%d", + mFrameRateFlexibilityTokenCount); + } + })); + return result; +} + +void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { + postMessageAsync(new LambdaMessage([&]() { + LOG_ALWAYS_FATAL_IF(mFrameRateFlexibilityTokenCount == 0, + "Failed tracking frame rate flexibility tokens"); + mFrameRateFlexibilityTokenCount--; + ALOGD("Frame rate flexibility token released. count=%d", mFrameRateFlexibilityTokenCount); + if (mFrameRateFlexibilityTokenCount == 0) { + // |mStateLock| not needed as we are on the main thread + const auto display = getDefaultDisplayDeviceLocked(); + status_t result = + setDesiredDisplayConfigSpecsInternal(display, {}, /*overridePolicy=*/true); + LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token"); + } + })); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 60904f640d..39976333ae 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -407,7 +407,8 @@ private: */ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; status_t dump(int fd, const Vector& args) override { return priorityDump(fd, args); } - bool callingThreadHasUnscopedSurfaceFlingerAccess() EXCLUDES(mStateLock); + bool callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermissionCache = true) + EXCLUDES(mStateLock); /* ------------------------------------------------------------------------ * ISurfaceComposer interface @@ -503,6 +504,7 @@ private: float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp& surface, float frameRate, int8_t compatibility) override; + status_t acquireFrameRateFlexibilityToken(sp* outToken) override; /* ------------------------------------------------------------------------ * DeathRecipient interface */ @@ -574,9 +576,9 @@ private: void setPowerModeInternal(const sp& display, int mode) REQUIRES(mStateLock); // Sets the desired display configs. - status_t setDesiredDisplayConfigSpecsInternal(const sp& display, - HwcConfigIndexType defaultConfig, - float minRefreshRate, float maxRefreshRate) + status_t setDesiredDisplayConfigSpecsInternal( + const sp& display, + const std::optional& policy, bool overridePolicy) EXCLUDES(mStateLock); // called on the main thread in response to setAutoLowLatencyMode() @@ -968,6 +970,8 @@ private: return doDump(fd, args, asProto); } + void onFrameRateFlexibilityTokenReleased(); + /* ------------------------------------------------------------------------ * VrFlinger */ @@ -1275,6 +1279,8 @@ private: std::atomic mInputDirty = true; void dirtyInput() { mInputDirty = true; } bool inputDirty() { return mInputDirty; } + + int mFrameRateFlexibilityTokenCount = 0; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index dd04076644..ce41291813 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -83,8 +83,8 @@ TEST_F(RefreshRateConfigsTest, invalidPolicy) { {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; auto refreshRateConfigs = std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); - ASSERT_LT(refreshRateConfigs->setPolicy(HwcConfigIndexType(10), 60, 60, nullptr), 0); - ASSERT_LT(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 20, 40, nullptr), 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { @@ -126,7 +126,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe ASSERT_EQ(expectedDefaultConfig, minRate60); ASSERT_EQ(expectedDefaultConfig, performanceRate60); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0); refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); @@ -155,7 +155,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { 90}; ASSERT_EQ(expectedPerformanceConfig, performanceRate); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); @@ -180,7 +180,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); } - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); { auto& current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); @@ -212,7 +212,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(expected60Config, @@ -224,7 +224,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(expected90Config, @@ -235,7 +235,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f))); EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0); EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(expected60Config, @@ -332,7 +332,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { &ignored)); lr.name = ""; - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected60Config, @@ -370,7 +370,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, &ignored)); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 90, 90, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected90Config, @@ -408,7 +408,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, &ignored)); - ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120, nullptr), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, @@ -1218,6 +1218,33 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_ExplicitDefault) { } } +TEST_F(RefreshRateConfigsTest, groupSwitching) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(configs, /*currentConfigId=*/HWC_CONFIG_ID_60); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitDefault; + layer.desiredRefreshRate = 90.0f; + layer.name = "90Hz ExplicitDefault"; + + bool touchConsidered; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered) + .configId); + + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + ASSERT_EQ(HWC_CONFIG_ID_90, + refreshRateConfigs->getRefreshRateForContentV2(layers, false, &touchConsidered) + .configId); +} + } // namespace } // namespace scheduler } // namespace android -- cgit v1.2.3-59-g8ed1b From ffcba5e3cabb9a3b3e69d188d74fa4e2f2919923 Mon Sep 17 00:00:00 2001 From: Dan Shi Date: Mon, 6 Apr 2020 16:15:58 -0700 Subject: Rename vts-core to vts Bug: 151896491 Test: presubmit check Exempt-From-Owner-Approval: This CL renames suite name vts-core to vts. It won't change test logic or behavior. Change-Id: I4522a350a0920badc649f02bf98bd6b01745dd77 --- libs/binder/tests/Android.bp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 3ee818734a..c7b75515cd 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -40,7 +40,7 @@ cc_test { }, srcs: ["binderDriverInterfaceTest.cpp"], - test_suites: ["device-tests", "vts-core"], + test_suites: ["device-tests", "vts"], } cc_test { @@ -69,7 +69,7 @@ cc_test { "libbinder", "libutils", ], - test_suites: ["device-tests", "vts-core"], + test_suites: ["device-tests", "vts"], require_root: true, } @@ -131,7 +131,7 @@ cc_test { "liblog", "libutils", ], - test_suites: ["device-tests", "vts-core"], + test_suites: ["device-tests", "vts"], require_root: true, } -- cgit v1.2.3-59-g8ed1b From 5a6d857f3361f46d58314ff45a074157b2600a92 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 23 Mar 2020 23:56:15 -0700 Subject: Fix filtering for screenshotting custom displays. Previously, filtering was computed for screenshots by checking if filtering was required for the DisplayDevice itself. That's correct for rendering custom display sizes since we need to upsample to the physical panel, but it's wrong for screenshotting to an output buffer where the logical transform does not involve a scale. Instead, we want to compare the source crop with the destination buffer size when determining whether we need to apply linear filtering. As part of this, some of the rendering math is now simpler. Rather than setting DisplaySettings::physicalDisplay and DisplaySettings::clip to be the same and explicitly computing the transform matrix in RenderEngine, we instead set DisplaySettings::clip to be the logical viewport. Then the global transform is implicitly applied as part of mapping the output in glViewport. This is because if the logical display is smaller than the screen size, with the previous behavior applying the global transform will scale up the layer stack to the physical display size. But if we want pixel-accurate screenshots we will need to downsample back down to the logical display size, which may cause errors. The math simplification will avoid that scenario entirely. This also means that screenshot code needs to be adjusted - some callers pass in a cropping rectangle that assumes the display screenshot is captured in portrait orientation. Other callers pass in a cropping rectangle relative to a particular layer's coordinate space. For each of those paths, the cropping rectangle must be transformed to the logical display space. This has also discovered a bug in setting the background fill of the screenshot, which has now been fixed. Bug: 129101431 Test: adb shell screepcap Test: Modify wm size and density, and run SurfaceViewTests#testMovingWhiteSurfaceView Test: Capture screenshots through vysor Test: Capture screenshots on Pixel 3XL with notch hide Test: Physically capture screenshots Test: Display rotations Test: SurfaceFlinger_test Test: librenderengine_test Test: libsurfaceflinger_unittest Test: libcompositionengine_test Change-Id: I7f4e98d4c5aa53a995fd7da70078a2e5ea43b14f --- libs/renderengine/gl/GLESRenderEngine.cpp | 5 +- .../include/renderengine/DisplaySettings.h | 12 +++- libs/renderengine/tests/RenderEngineTest.cpp | 19 +++--- services/surfaceflinger/BufferLayer.cpp | 33 ++++++++++ services/surfaceflinger/BufferLayer.h | 2 + services/surfaceflinger/DisplayDevice.cpp | 10 ++- services/surfaceflinger/DisplayDevice.h | 75 ++++++++++----------- services/surfaceflinger/Layer.h | 13 ++++ services/surfaceflinger/RenderArea.h | 7 +- services/surfaceflinger/SurfaceFlinger.cpp | 76 +++++----------------- .../tests/MultiDisplayLayerBounds_test.cpp | 2 +- .../tests/unittests/DisplayTransactionTest.cpp | 4 +- 12 files changed, 133 insertions(+), 125 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e73f245fab..d56a82f4d7 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -795,6 +795,7 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, // Firstly, we need to convert the coordination from layer native coordination space to // device coordination space. + // TODO(143929254): Verify that this transformation is correct const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform; const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0); const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0); @@ -1015,8 +1016,8 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, setOutputDataSpace(display.outputDataspace); setDisplayMaxLuminance(display.maxLuminance); - mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform; - mState.projectionMatrix = projectionMatrix; + const mat4 projectionMatrix = + ui::Transform(display.orientation).asMatrix4() * mState.projectionMatrix; if (!display.clearRegion.isEmpty()) { glDisable(GL_BLEND); fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0); diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index c4a29a9c51..c0766ab5b3 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -41,6 +41,13 @@ struct DisplaySettings { Rect clip = Rect::INVALID_RECT; // Global transform to apply to all layers. + // The global transform is assumed to automatically apply when projecting + // the clip rectangle onto the physical display; however, this should be + // explicitly provided to perform CPU-side optimizations such as computing + // scissor rectangles for rounded corners which require transformation to + // the phsical display space. + // + // This transform is also assumed to include the orientation flag below. mat4 globalTransform = mat4(); // Maximum luminance pulled from the display's HDR capabilities. @@ -60,7 +67,10 @@ struct DisplaySettings { // rendered layers. Region clearRegion = Region::INVALID_REGION; - // The orientation of the physical display. + // An additional orientation flag to be applied after clipping the output. + // By way of example, this may be used for supporting fullscreen screenshot + // capture of a device in landscape while the buffer is in portrait + // orientation. uint32_t orientation = ui::Transform::ROT_0; }; diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index afcbc50584..ce9131d890 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -298,7 +298,7 @@ struct RenderEngineTest : public ::testing::Test { void fillBufferPhysicalOffset(); template - void fillBufferCheckers(mat4 transform); + void fillBufferCheckers(uint32_t rotation); template void fillBufferCheckersRotate0(); @@ -509,12 +509,12 @@ void RenderEngineTest::fillBufferPhysicalOffset() { } template -void RenderEngineTest::fillBufferCheckers(mat4 transform) { +void RenderEngineTest::fillBufferCheckers(uint32_t orientationFlag) { renderengine::DisplaySettings settings; settings.physicalDisplay = fullscreenRect(); // Here logical space is 2x2 settings.clip = Rect(2, 2); - settings.globalTransform = transform; + settings.orientation = orientationFlag; std::vector layers; @@ -545,7 +545,7 @@ void RenderEngineTest::fillBufferCheckers(mat4 transform) { template void RenderEngineTest::fillBufferCheckersRotate0() { - fillBufferCheckers(mat4()); + fillBufferCheckers(ui::Transform::ROT_0); expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0, 255); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH, @@ -561,8 +561,7 @@ void RenderEngineTest::fillBufferCheckersRotate0() { template void RenderEngineTest::fillBufferCheckersRotate90() { - mat4 matrix = mat4(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 1); - fillBufferCheckers(matrix); + fillBufferCheckers(ui::Transform::ROT_90); expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 255, 0, 255); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH, @@ -578,8 +577,7 @@ void RenderEngineTest::fillBufferCheckersRotate90() { template void RenderEngineTest::fillBufferCheckersRotate180() { - mat4 matrix = mat4(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 2, 2, 0, 1); - fillBufferCheckers(matrix); + fillBufferCheckers(ui::Transform::ROT_180); expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 0, 0); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH, @@ -595,8 +593,7 @@ void RenderEngineTest::fillBufferCheckersRotate180() { template void RenderEngineTest::fillBufferCheckersRotate270() { - mat4 matrix = mat4(0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1); - fillBufferCheckers(matrix); + fillBufferCheckers(ui::Transform::ROT_270); expectBufferColor(Rect(0, 0, DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 0, 0, 255, 255); expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 2, 0, DEFAULT_DISPLAY_WIDTH, @@ -928,7 +925,7 @@ void RenderEngineTest::clearLeftRegion() { // Here logical space is 4x4 settings.clip = Rect(4, 4); settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1)); - settings.clearRegion = Region(Rect(1, 1)); + settings.clearRegion = Region(Rect(2, 4)); std::vector layers; // dummy layer, without bounds should not render anything renderengine::LayerSettings layer; diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index a32bc2b6ce..5f90566df2 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -618,6 +618,39 @@ bool BufferLayer::needsFiltering(const sp& displayDevice) c sourceCrop.getWidth() != displayFrame.getWidth(); } +bool BufferLayer::needsFilteringForScreenshots(const sp& displayDevice, + const ui::Transform& inverseParentTransform) const { + // If we are not capturing based on the state of a known display device, + // just return false. + if (displayDevice == nullptr) { + return false; + } + + const auto outputLayer = findOutputLayerForDisplay(displayDevice); + if (outputLayer == nullptr) { + return false; + } + + // We need filtering if the sourceCrop rectangle size does not match the + // viewport rectangle size (not a 1:1 render) + const auto& compositionState = outputLayer->getState(); + const ui::Transform& displayTransform = displayDevice->getTransform(); + const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse(); + // Undo the transformation of the displayFrame so that we're back into + // layer-stack space. + const Rect frame = inverseTransform.transform(compositionState.displayFrame); + const FloatRect sourceCrop = compositionState.sourceCrop; + + int32_t frameHeight = frame.getHeight(); + int32_t frameWidth = frame.getWidth(); + // If the display transform had a rotational component then undo the + // rotation so that the orientation matches the source crop. + if (displayTransform.getOrientation() & ui::Transform::ROT_90) { + std::swap(frameHeight, frameWidth); + } + return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth; +} + uint64_t BufferLayer::getHeadFrameNumber(nsecs_t expectedPresentTime) const { if (hasFrameUpdate()) { return getFrameNumber(expectedPresentTime); diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index fbec6ee9d9..56bab1bbbe 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -208,6 +208,8 @@ protected: private: // Returns true if this layer requires filtering bool needsFiltering(const sp& displayDevice) const override; + bool needsFilteringForScreenshots(const sp& displayDevice, + const ui::Transform& inverseParentTransform) const override; // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame // and its parent layer is not bounded diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b72214d307..b81eb181ae 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -220,13 +220,11 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect const bool needsFiltering = (!globalTransform.preserveRects() || (type >= ui::Transform::SCALE)); - Rect sourceClip = globalTransform.transform(viewport); - if (sourceClip.isEmpty()) { - sourceClip = displayBounds; + const Rect& sourceClip = viewport; + Rect destinationClip = globalTransform.transform(viewport); + if (destinationClip.isEmpty()) { + destinationClip = displayBounds; } - // For normal display use we always set the source and destination clip - // rectangles to the same values. - const Rect& destinationClip = sourceClip; uint32_t transformOrientation; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 397fedcb88..e670d78126 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -244,14 +244,12 @@ public: uint32_t reqHeight, ui::Dataspace reqDataSpace, RotationFlags rotation, bool allowSecureLayers = true) : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace, - display->getViewport(), - applyInversePhysicalOrientation(rotation, - display->getPhysicalOrientation())), + display->getViewport(), applyDeviceOrientation(rotation, display)), mDisplay(std::move(display)), mSourceCrop(sourceCrop), mAllowSecureLayers(allowSecureLayers) {} - const ui::Transform& getTransform() const override { return mDisplay->getTransform(); } + const ui::Transform& getTransform() const override { return mTransform; } Rect getBounds() const override { return mDisplay->getBounds(); } int getHeight() const override { return mDisplay->getHeight(); } int getWidth() const override { return mDisplay->getWidth(); } @@ -259,15 +257,9 @@ public: sp getDisplayDevice() const override { return mDisplay; } bool needsFiltering() const override { - // check if the projection from the logical display to the physical - // display needs filtering - if (mDisplay->needsFiltering()) { - return true; - } - - // check if the projection from the logical render area (i.e., the - // physical display) to the physical render area requires filtering - const Rect sourceCrop = getSourceCrop(); + // check if the projection from the logical render area + // to the physical render area requires filtering + const Rect& sourceCrop = getSourceCrop(); int width = sourceCrop.width(); int height = sourceCrop.height(); if (getRotationFlags() & ui::Transform::ROT_90) { @@ -282,36 +274,44 @@ public: return mDisplay->getSourceClip(); } - // Recompute the device transformation for the source crop. + // If there is a source crop provided then it is assumed that the device + // was in portrait orientation. This may not logically be true, so + // correct for the orientation error by undoing the rotation + + ui::Rotation logicalOrientation = mDisplay->getOrientation(); + if (logicalOrientation == ui::Rotation::Rotation90) { + logicalOrientation = ui::Rotation::Rotation270; + } else if (logicalOrientation == ui::Rotation::Rotation270) { + logicalOrientation = ui::Rotation::Rotation90; + } + + const auto flags = ui::Transform::toRotationFlags(logicalOrientation); + int width = mDisplay->getSourceClip().getWidth(); + int height = mDisplay->getSourceClip().getHeight(); ui::Transform rotation; - ui::Transform translatePhysical; - ui::Transform translateLogical; - ui::Transform scale; - const Rect& viewport = mDisplay->getViewport(); - const Rect& sourceClip = mDisplay->getSourceClip(); - const Rect& frame = mDisplay->getFrame(); - - const auto flags = ui::Transform::toRotationFlags(mDisplay->getPhysicalOrientation()); - rotation.set(flags, getWidth(), getHeight()); - - translateLogical.set(-viewport.left, -viewport.top); - translatePhysical.set(sourceClip.left, sourceClip.top); - scale.set(frame.getWidth() / float(viewport.getWidth()), 0, 0, - frame.getHeight() / float(viewport.getHeight())); - const ui::Transform finalTransform = - rotation * translatePhysical * scale * translateLogical; - return finalTransform.transform(mSourceCrop); + rotation.set(flags, width, height); + return rotation.transform(mSourceCrop); } private: - static RotationFlags applyInversePhysicalOrientation(RotationFlags orientation, - ui::Rotation physicalOrientation) { + static RotationFlags applyDeviceOrientation(RotationFlags orientationFlag, + const sp& device) { uint32_t inverseRotate90 = 0; uint32_t inverseReflect = 0; - switch (physicalOrientation) { + // Reverse the logical orientation. + ui::Rotation logicalOrientation = device->getOrientation(); + if (logicalOrientation == ui::Rotation::Rotation90) { + logicalOrientation = ui::Rotation::Rotation270; + } else if (logicalOrientation == ui::Rotation::Rotation270) { + logicalOrientation = ui::Rotation::Rotation90; + } + + const ui::Rotation orientation = device->getPhysicalOrientation() + logicalOrientation; + + switch (orientation) { case ui::ROTATION_0: - return orientation; + return orientationFlag; case ui::ROTATION_90: inverseRotate90 = ui::Transform::ROT_90; @@ -327,8 +327,8 @@ private: break; } - const uint32_t rotate90 = orientation & ui::Transform::ROT_90; - uint32_t reflect = orientation & ui::Transform::ROT_180; + const uint32_t rotate90 = orientationFlag & ui::Transform::ROT_90; + uint32_t reflect = orientationFlag & ui::Transform::ROT_180; // Apply reflection for double rotation. if (rotate90 & inverseRotate90) { @@ -342,6 +342,7 @@ private: const sp mDisplay; const Rect mSourceCrop; const bool mAllowSecureLayers; + const ui::Transform mTransform = ui::Transform(); }; } // namespace android diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index be80f7821f..92ac015005 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -535,6 +535,19 @@ public: } virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; } virtual bool needsFiltering(const sp&) const { return false; } + // True if this layer requires filtering + // This method is distinct from needsFiltering() in how the filter + // requirement is computed. needsFiltering() compares displayFrame and crop, + // where as this method transforms the displayFrame to layer-stack space + // first. This method should be used if there is no physical display to + // project onto when taking screenshots, as the filtering requirements are + // different. + // If the parent transform needs to be undone when capturing the layer, then + // the inverse parent transform is also required. + virtual bool needsFilteringForScreenshots(const sp&, + const ui::Transform&) const { + return false; + } // This layer is not a clone, but it's the parent to the cloned hierarchy. The // variable mClonedChild represents the top layer that will be cloned so this diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h index 9b3a9f4309..6b0455ae87 100644 --- a/services/surfaceflinger/RenderArea.h +++ b/services/surfaceflinger/RenderArea.h @@ -61,10 +61,9 @@ public: // render area. It can be larger than the logical render area. It can // also be optionally rotated. // - // Layers are first clipped to the source crop (in addition to being - // clipped to the logical render area already). The source crop and the - // layers are then rotated around the center of the source crop, and - // scaled to the physical render area linearly. + // The source crop is specified in layer space (when rendering a layer and + // its children), or in layer-stack space (when rendering all layers visible + // on the display). virtual Rect getSourceCrop() const = 0; // Returns the rotation of the source crop and the layers. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e22bc61d50..aa0005dfa6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5357,7 +5357,6 @@ status_t SurfaceFlinger::captureScreen(const sp& displayToken, DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace, renderAreaRotation, captureSecureLayers); - auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display, std::placeholders::_1); return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, @@ -5485,10 +5484,7 @@ status_t SurfaceFlinger::captureLayers( mFlinger(flinger), mChildrenOnly(childrenOnly) {} const ui::Transform& getTransform() const override { return mTransform; } - Rect getBounds() const override { - const Layer::State& layerState(mLayer->getDrawingState()); - return mLayer->getBufferSize(layerState); - } + Rect getBounds() const override { return mLayer->getBufferSize(mLayer->getDrawingState()); } int getHeight() const override { return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight(); } @@ -5531,9 +5527,8 @@ status_t SurfaceFlinger::captureLayers( mTransform = mLayer->getTransform().inverse(); drawLayers(); } else { - Rect bounds = getBounds(); - uint32_t w = static_cast(bounds.getWidth()); - uint32_t h = static_cast(bounds.getHeight()); + uint32_t w = static_cast(getWidth()); + uint32_t h = static_cast(getHeight()); // In the "childrenOnly" case we reparent the children to a screenshot // layer which has no properties set and which does not draw. sp screenshotParentLayer = @@ -5748,9 +5743,9 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, const auto reqWidth = renderArea.getReqWidth(); const auto reqHeight = renderArea.getReqHeight(); - const auto rotation = renderArea.getRotationFlags(); - const auto transform = renderArea.getTransform(); const auto sourceCrop = renderArea.getSourceCrop(); + const auto transform = renderArea.getTransform(); + const auto rotation = renderArea.getRotationFlags(); const auto& displayViewport = renderArea.getDisplayViewport(); renderengine::DisplaySettings clientCompositionDisplay; @@ -5760,55 +5755,8 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, // buffer bounds. clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight); clientCompositionDisplay.clip = sourceCrop; - clientCompositionDisplay.globalTransform = transform.asMatrix4(); - - // Now take into account the rotation flag. We append a transform that - // rotates the layer stack about the origin, then translate by buffer - // boundaries to be in the right quadrant. - mat4 rotMatrix; - int displacementX = 0; - int displacementY = 0; - float rot90InRadians = 2.0f * static_cast(M_PI) / 4.0f; - switch (rotation) { - case ui::Transform::ROT_90: - rotMatrix = mat4::rotate(rot90InRadians, vec3(0, 0, 1)); - displacementX = renderArea.getBounds().getHeight(); - break; - case ui::Transform::ROT_180: - rotMatrix = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)); - displacementY = renderArea.getBounds().getWidth(); - displacementX = renderArea.getBounds().getHeight(); - break; - case ui::Transform::ROT_270: - rotMatrix = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)); - displacementY = renderArea.getBounds().getWidth(); - break; - default: - break; - } - - // We need to transform the clipping window into the right spot. - // First, rotate the clipping rectangle by the rotation hint to get the - // right orientation - const vec4 clipTL = vec4(sourceCrop.left, sourceCrop.top, 0, 1); - const vec4 clipBR = vec4(sourceCrop.right, sourceCrop.bottom, 0, 1); - const vec4 rotClipTL = rotMatrix * clipTL; - const vec4 rotClipBR = rotMatrix * clipBR; - const int newClipLeft = std::min(rotClipTL[0], rotClipBR[0]); - const int newClipTop = std::min(rotClipTL[1], rotClipBR[1]); - const int newClipRight = std::max(rotClipTL[0], rotClipBR[0]); - const int newClipBottom = std::max(rotClipTL[1], rotClipBR[1]); - - // Now reposition the clipping rectangle with the displacement vector - // computed above. - const mat4 displacementMat = mat4::translate(vec4(displacementX, displacementY, 0, 1)); - clientCompositionDisplay.clip = - Rect(newClipLeft + displacementX, newClipTop + displacementY, - newClipRight + displacementX, newClipBottom + displacementY); - - mat4 clipTransform = displacementMat * rotMatrix; - clientCompositionDisplay.globalTransform = - clipTransform * clientCompositionDisplay.globalTransform; + clientCompositionDisplay.globalTransform = mat4(); + clientCompositionDisplay.orientation = rotation; clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace(); clientCompositionDisplay.maxLuminance = DisplayDevice::sDefaultMaxLumiance; @@ -5818,7 +5766,8 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, compositionengine::LayerFE::LayerSettings fillLayer; fillLayer.source.buffer.buffer = nullptr; fillLayer.source.solidColor = half3(0.0, 0.0, 0.0); - fillLayer.geometry.boundaries = FloatRect(0.0, 0.0, 1.0, 1.0); + fillLayer.geometry.boundaries = + FloatRect(sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom); fillLayer.alpha = half(alpha); clientCompositionLayers.push_back(fillLayer); @@ -5830,7 +5779,8 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, useIdentityTransform, - layer->needsFiltering(renderArea.getDisplayDevice()) || renderArea.needsFiltering(), + layer->needsFilteringForScreenshots(renderArea.getDisplayDevice(), transform) || + renderArea.needsFiltering(), renderArea.isSecure(), supportProtectedContent, clearRegion, @@ -5842,6 +5792,10 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, std::vector results = layer->prepareClientCompositionList(targetSettings); if (results.size() > 0) { + for (auto& settings : results) { + settings.geometry.positionTransform = + transform.asMatrix4() * settings.geometry.positionTransform; + } clientCompositionLayers.insert(clientCompositionLayers.end(), std::make_move_iterator(results.begin()), std::make_move_iterator(results.end())); diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp index f8a5b4094d..06e8761d43 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -104,7 +104,7 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) { // Verify color layer renders correctly on virtual display. ScreenCapture::captureScreen(&sc, mVirtualDisplay); sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor); - sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 0}); + sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 255}); } TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 24eeac70a4..ea3d744930 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1504,7 +1504,7 @@ public: mHardwareDisplaySize.height), compositionState.transform); EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation); - EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip); + EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.sourceClip); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip); // For 90, the frame and viewport have the hardware display size width and height swapped EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame); @@ -1531,7 +1531,7 @@ public: mHardwareDisplaySize.height), compositionState.transform); EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation); - EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip); + EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.sourceClip); EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip); // For 270, the frame and viewport have the hardware display size width and height swapped EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame); -- cgit v1.2.3-59-g8ed1b From d4bf795effcc3cb719992d03b856ba6dfd34c8b6 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 6 Apr 2020 20:28:16 -0700 Subject: Remove DisplaySettings::globalTransform The globalTransform can be described entirely in terms of the clip rectangle, physical display projection, and orientation, so the extra field isn't needed. We only need it when handling rounded corners so compute the transform there. Bug: 137209275 Bug: 143929254 Test: slow swipe to recents to visually check rounded corners Test: adb screencap during animations Test: above tests in portrait and landscape orientation Test: librenderengine_test Change-Id: I05f63cc6ccbe7403fe158c86a8a3db5bf932e812 --- libs/renderengine/gl/GLESRenderEngine.cpp | 67 ++++++++++++++++------ .../include/renderengine/DisplaySettings.h | 18 +----- libs/renderengine/tests/RenderEngineTest.cpp | 1 - .../CompositionEngine/src/Output.cpp | 1 - .../CompositionEngine/tests/OutputTest.cpp | 19 +++--- services/surfaceflinger/SurfaceFlinger.cpp | 1 - 6 files changed, 59 insertions(+), 48 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index d56a82f4d7..36a54a7464 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -793,35 +793,66 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle. FloatRect bounds = layer.geometry.roundedCornersCrop; - // Firstly, we need to convert the coordination from layer native coordination space to - // device coordination space. - // TODO(143929254): Verify that this transformation is correct - const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform; - const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0); - const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0); - const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate; - const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate; - bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1], - rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]); - - // Secondly, if the display is rotated, we need to undo the rotation on coordination and - // align the (left, top) and (right, bottom) coordination with the device coordination - // space. + // Explicitly compute the transform from the clip rectangle to the physical + // display. Normally, this is done in glViewport but we explicitly compute + // it here so that we can get the scissor bounds correct. + const Rect& source = display.clip; + const Rect& destination = display.physicalDisplay; + // Here we compute the following transform: + // 1. Translate the top left corner of the source clip to (0, 0) + // 2. Rotate the clip rectangle about the origin in accordance with the + // orientation flag + // 3. Translate the top left corner back to the origin. + // 4. Scale the clip rectangle to the destination rectangle dimensions + // 5. Translate the top left corner to the destination rectangle's top left + // corner. + const mat4 translateSource = mat4::translate(vec4(-source.left, -source.top, 0, 1)); + mat4 rotation; + int displacementX = 0; + int displacementY = 0; + float destinationWidth = static_cast(destination.getWidth()); + float destinationHeight = static_cast(destination.getHeight()); + float sourceWidth = static_cast(source.getWidth()); + float sourceHeight = static_cast(source.getHeight()); + const float rot90InRadians = 2.0f * static_cast(M_PI) / 4.0f; switch (display.orientation) { case ui::Transform::ROT_90: - std::swap(bounds.left, bounds.right); + rotation = mat4::rotate(rot90InRadians, vec3(0, 0, 1)); + displacementX = source.getHeight(); + std::swap(sourceHeight, sourceWidth); break; case ui::Transform::ROT_180: - std::swap(bounds.left, bounds.right); - std::swap(bounds.top, bounds.bottom); + rotation = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)); + displacementY = source.getHeight(); + displacementX = source.getWidth(); break; case ui::Transform::ROT_270: - std::swap(bounds.top, bounds.bottom); + rotation = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)); + displacementY = source.getWidth(); + std::swap(sourceHeight, sourceWidth); break; default: break; } + const mat4 intermediateTranslation = mat4::translate(vec4(displacementX, displacementY, 0, 1)); + const mat4 scale = mat4::scale( + vec4(destinationWidth / sourceWidth, destinationHeight / sourceHeight, 1, 1)); + const mat4 translateDestination = + mat4::translate(vec4(destination.left, destination.top, 0, 1)); + const mat4 globalTransform = + translateDestination * scale * intermediateTranslation * rotation * translateSource; + + const mat4 transformMatrix = globalTransform * layer.geometry.positionTransform; + const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0); + const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0); + const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate; + const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate; + bounds = FloatRect(std::min(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]), + std::min(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1]), + std::max(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]), + std::max(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1])); + // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners // and the middle part without rounded corners. const int32_t radius = ceil(layer.geometry.roundedCornersRadius); diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index c0766ab5b3..ca16d2c727 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -40,16 +40,6 @@ struct DisplaySettings { // z=1. Rect clip = Rect::INVALID_RECT; - // Global transform to apply to all layers. - // The global transform is assumed to automatically apply when projecting - // the clip rectangle onto the physical display; however, this should be - // explicitly provided to perform CPU-side optimizations such as computing - // scissor rectangles for rounded corners which require transformation to - // the phsical display space. - // - // This transform is also assumed to include the orientation flag below. - mat4 globalTransform = mat4(); - // Maximum luminance pulled from the display's HDR capabilities. float maxLuminance = 1.0f; @@ -62,9 +52,7 @@ struct DisplaySettings { mat4 colorTransform = mat4(); // Region that will be cleared to (0, 0, 0, 1) prior to rendering. - // RenderEngine will transform the clearRegion passed in here, by - // globalTransform, so that it will be in the same coordinate space as the - // rendered layers. + // This is specified in layer-stack space. Region clearRegion = Region::INVALID_REGION; // An additional orientation flag to be applied after clipping the output. @@ -76,8 +64,7 @@ struct DisplaySettings { static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { return lhs.physicalDisplay == rhs.physicalDisplay && lhs.clip == rhs.clip && - lhs.globalTransform == rhs.globalTransform && lhs.maxLuminance == rhs.maxLuminance && - lhs.outputDataspace == rhs.outputDataspace && + lhs.maxLuminance == rhs.maxLuminance && lhs.outputDataspace == rhs.outputDataspace && lhs.colorTransform == rhs.colorTransform && lhs.clearRegion.hasSameRects(rhs.clearRegion) && lhs.orientation == rhs.orientation; } @@ -89,7 +76,6 @@ static inline void PrintTo(const DisplaySettings& settings, ::std::ostream* os) PrintTo(settings.physicalDisplay, os); *os << "\n .clip = "; PrintTo(settings.clip, os); - *os << "\n .globalTransform = " << settings.globalTransform; *os << "\n .maxLuminance = " << settings.maxLuminance; *os << "\n .outputDataspace = "; PrintTo(settings.outputDataspace, os); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index ce9131d890..f5bf014db1 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -924,7 +924,6 @@ void RenderEngineTest::clearLeftRegion() { settings.physicalDisplay = fullscreenRect(); // Here logical space is 4x4 settings.clip = Rect(4, 4); - settings.globalTransform = mat4::scale(vec4(2, 4, 0, 1)); settings.clearRegion = Region(Rect(2, 4)); std::vector layers; // dummy layer, without bounds should not render anything diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 248933e8f0..34d0cb2b67 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -829,7 +829,6 @@ std::optional Output::composeSurfaces( renderengine::DisplaySettings clientCompositionDisplay; clientCompositionDisplay.physicalDisplay = outputState.destinationClip; clientCompositionDisplay.clip = outputState.sourceClip; - clientCompositionDisplay.globalTransform = outputState.transform.asMatrix4(); clientCompositionDisplay.orientation = outputState.orientation; clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut() ? outputState.dataspace diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 63bb459dbe..1c9cd9c0c0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3100,9 +3100,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposi .andIfUsesHdr(true) .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, - mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, - mat4(), Region::INVALID_REGION, - kDefaultOutputOrientation}) + kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), + Region::INVALID_REGION, kDefaultOutputOrientation}) .execute() .expectAFenceWasReturned(); } @@ -3112,9 +3111,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComp .andIfUsesHdr(false) .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, - mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, - mat4(), Region::INVALID_REGION, - kDefaultOutputOrientation}) + kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), + Region::INVALID_REGION, kDefaultOutputOrientation}) .execute() .expectAFenceWasReturned(); } @@ -3124,7 +3122,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientCo .andIfUsesHdr(true) .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, - mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, + kDefaultMaxLuminance, kDefaultOutputDataspace, kDefaultColorTransformMat, Region::INVALID_REGION, kDefaultOutputOrientation}) .execute() @@ -3136,7 +3134,7 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClien .andIfUsesHdr(false) .andIfSkipColorTransform(false) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, - mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, + kDefaultMaxLuminance, kDefaultOutputDataspace, kDefaultColorTransformMat, Region::INVALID_REGION, kDefaultOutputOrientation}) .execute() @@ -3149,9 +3147,8 @@ TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, .andIfUsesHdr(true) .andIfSkipColorTransform(true) .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip, - mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace, - mat4(), Region::INVALID_REGION, - kDefaultOutputOrientation}) + kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(), + Region::INVALID_REGION, kDefaultOutputOrientation}) .execute() .expectAFenceWasReturned(); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index aa0005dfa6..060185bc87 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5755,7 +5755,6 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, // buffer bounds. clientCompositionDisplay.physicalDisplay = Rect(reqWidth, reqHeight); clientCompositionDisplay.clip = sourceCrop; - clientCompositionDisplay.globalTransform = mat4(); clientCompositionDisplay.orientation = rotation; clientCompositionDisplay.outputDataspace = renderArea.getReqDataSpace(); -- cgit v1.2.3-59-g8ed1b From db26a6b0ba85993acc0c92e7ab1c3cf6988512e5 Mon Sep 17 00:00:00 2001 From: Jeongik Cha Date: Wed, 8 Apr 2020 21:46:00 +0900 Subject: Include Rect.h explictly After freezing android.hardware.graphics.common, PlaneLayout.h doesn't include Rect.h because header by redunant import is omitted. (b/153527738) So include Rect.h explictly Test: m Bug: 153510960 Change-Id: If513d1339452916d01b6571f0253d7da9fddea49 --- libs/gralloc/types/include/gralloctypes/Gralloc4.h | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index 5ec4d0df3c..8d12754d79 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From bbc8562601d272343df7649f2561ad475f8639f0 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 8 Apr 2020 10:45:12 -0700 Subject: SurfaceComposerClient BLAST Transactions: Correctly merge mContainsBuffer If we merge a transaction which does not contain a buffer in to a transaction which already contained a buffer, the resulting transaction still needs to have mContainsBuffer=true, otherwise we won't properly cache the buffers. Bug: 153561718 Test: Existing tests pass. Manual test of BLASTSyncEngine. Change-Id: Ic63aba390757285730cb19406dc5c6b73d0c3437 --- libs/gui/SurfaceComposerClient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 2307fbf56b..8a7412e116 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -507,7 +507,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mInputWindowCommands.merge(other.mInputWindowCommands); - mContainsBuffer = other.mContainsBuffer; + mContainsBuffer |= other.mContainsBuffer; mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; other.clear(); return *this; -- cgit v1.2.3-59-g8ed1b From 158531d044690c52dfd1889e699a5f723df44b95 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 8 Apr 2020 10:53:30 -0700 Subject: SurfaceComposerClient BLAST: cacheBuffers before writing transaction to parcel. If we write the Transaction to a parcel, we want to ensure the Buffers are cached before crossing the IPC boundary. Otherwise the receiving party will cache the buffers but is unlikely to use them again as they are owned by the other process. You may be asking yourself, is this const cast safe? Const cast is safe up until the point where you try and write to an object that was originally const at which point we enter undefined behavior. In this case we are safe though, because there are two possibilities: 1. The SurfaceComposerClient::Transaction was originally non-const. Safe. 2. It was originall const! In this case not only was it useless, but it by definition contains no composer states and so cacheBuffers will not perform any writes. Bug: 153561718 Test: Existing tests pass. Manual test of BLAST Sync Engine. Change-Id: Ibb5425955f3d8c40f8c227d8911989dd76f8afe4 --- libs/gui/SurfaceComposerClient.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8a7412e116..e89863f48b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -430,6 +430,19 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel } status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const { + // If we write the Transaction to a parcel, we want to ensure the Buffers are cached + // before crossing the IPC boundary. Otherwise the receiving party will cache the buffers + // but is unlikely to use them again as they are owned by the other process. + // You may be asking yourself, is this const cast safe? Const cast is safe up + // until the point where you try and write to an object that was originally const at which + // point we enter undefined behavior. In this case we are safe though, because there are + // two possibilities: + // 1. The SurfaceComposerClient::Transaction was originally non-const. Safe. + // 2. It was originall const! In this case not only was it useless, but it by definition + // contains no composer states and so cacheBuffers will not perform any writes. + + const_cast(this)->cacheBuffers(); + parcel->writeUint32(mForceSynchronous); parcel->writeUint32(mTransactionNestCount); parcel->writeBool(mAnimation); -- cgit v1.2.3-59-g8ed1b From 2803792bfa2dbefc2bf03f9417d13aaae2ce5673 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 8 Apr 2020 10:57:07 -0700 Subject: SurfaceComposerClient BLAST: Avoid recaching buffers. cacheBuffers works like this: 1. Look for any State with eBufferChanged 2. If it has a cache entry clear eBufferChanged and set the cache 3. If it doesn't have an entry leave eBufferChanged set, but also set the cache so we can use it next time. In the third case where we don't clear eBufferChanged we might attempt to recache buffers that have already been cached. This might happen in the wrong process. Bug: 153561718 Test: Existing tests pass. BLAST Sync Engine manual test. Change-Id: Ibe02e76d40fedef46a2418587e28e598d6e2c614 --- libs/gui/SurfaceComposerClient.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e89863f48b..605c2e8848 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -560,6 +560,11 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { layer_state_t* s = getLayerState(handle); if (!(s->what & layer_state_t::eBufferChanged)) { continue; + } else if (s->what & layer_state_t::eCachedBufferChanged) { + // If eBufferChanged and eCachedBufferChanged are both trued then that means + // we already cached the buffer in a previous call to cacheBuffers, perhaps + // from writeToParcel on a Transaction that was merged in to this one. + continue; } // Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste -- cgit v1.2.3-59-g8ed1b From 3bb979136595c6132d6c3b2a2aacac5bf352c4ef Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 9 Apr 2020 10:40:10 -0700 Subject: Check for no error in getting planeLayout in lock Bug: 153375197 Test: build, boot, libui_test Change-Id: I47715b31d759367f22ca14598e43b078094d9d75 --- libs/ui/Gralloc4.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp index 6fd4b80f17..c7032903de 100644 --- a/libs/ui/Gralloc4.cpp +++ b/libs/ui/Gralloc4.cpp @@ -202,7 +202,7 @@ status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, cons std::vector planeLayouts; status_t err = getPlaneLayouts(bufferHandle, &planeLayouts); - if (err != NO_ERROR && !planeLayouts.empty()) { + if (err == NO_ERROR && !planeLayouts.empty()) { if (outBytesPerPixel) { int32_t bitsPerPixel = planeLayouts.front().sampleIncrementInBits; for (const auto& planeLayout : planeLayouts) { -- cgit v1.2.3-59-g8ed1b From fa229841b62faf1adbb631cca3edc57df5c47885 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Fri, 10 Apr 2020 10:42:02 -0700 Subject: Reduce number or blur passes UX radius requirements were relaxed from 250px to 150px. This means that we don't need as many passes anymore to achieve the effect. Test: visual Bug: 152952628 Change-Id: I3a7cc152554636207c643a0c0cdd5c672f094c4f --- libs/renderengine/gl/filters/BlurFilter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 36e5a7730b..7e0819fcf9 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -38,7 +38,7 @@ public: // Downsample FBO to improve performance static constexpr float kFboScale = 0.25f; // Maximum number of render passes - static constexpr uint32_t kMaxPasses = 6; + static constexpr uint32_t kMaxPasses = 4; // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited // image, up to this radius. static constexpr float kMaxCrossFadeRadius = 30.0f; -- cgit v1.2.3-59-g8ed1b From 03f7b892ebc5980f5a8225d8cb44396087719554 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 13 Apr 2020 12:55:44 +0900 Subject: Mark some aidl_interface modules as unstable With b/152655547, all aidl_interface modules are considered as stable unless it is explicitly with "unstable: true". This change marks the aidl_interface that are not used across updatable module bounraries as unstable, so that the build system does not run the API dumping/checking on them. Bug: 152655547 Test: m Change-Id: Ib99b57fde95887d1725ef7a4bdd3daf979aa059b --- libs/binder/Android.bp | 1 + libs/binder/ndk/test/Android.bp | 2 ++ libs/binder/tests/Android.bp | 1 + libs/binderthreadstate/Android.bp | 1 + 4 files changed, 5 insertions(+) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index e6cfeb4943..72982824f4 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -170,6 +170,7 @@ filegroup { aidl_interface { name: "libbinder_aidl_test_stub", + unstable: true, local_include_dir: "aidl", srcs: [":libbinder_aidl"], vendor_available: true, diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index cb4b20ff9d..5f5265c90e 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -92,6 +92,7 @@ cc_test { aidl_interface { name: "IBinderVendorDoubleLoadTest", + unstable: true, vendor: true, srcs: [ "IBinderVendorDoubleLoadTest.aidl", @@ -100,6 +101,7 @@ aidl_interface { aidl_interface { name: "IBinderNdkUnitTest", + unstable: true, srcs: [ "IBinderNdkUnitTest.aidl", "IEmpty.aidl", diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index c7b75515cd..69fdd7c5d8 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -137,6 +137,7 @@ cc_test { aidl_interface { name: "binderStabilityTestIface", + unstable: true, srcs: [ "IBinderStabilityTest.aidl", ], diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp index c1861104d3..5eb509c4a0 100644 --- a/libs/binderthreadstate/Android.bp +++ b/libs/binderthreadstate/Android.bp @@ -39,6 +39,7 @@ hidl_package_root { aidl_interface { name: "binderthreadstateutilstest.aidl", + unstable: true, srcs: ["IAidlStuff.aidl"], } -- cgit v1.2.3-59-g8ed1b From 6077425c5ceaf923a07261e1ce5a662c97080185 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 10 Apr 2020 15:25:01 -0700 Subject: libbinder: avoid re-registering callback This code assumes that it is only registered once, and so in some cases, the service wasn't shutting down. Bug: 140310064 Test: aidl_lazy_test Change-Id: I19474e105b4c4b3669499ac71c8cf22b67a0176b Merged-In: I19474e105b4c4b3669499ac71c8cf22b67a0176b --- libs/binder/LazyServiceRegistrar.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index 74aece81f7..6f49aa1607 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -82,12 +82,12 @@ bool ClientCounterCallback::registerService(const sp& service, const st return false; } - if (!manager->registerClientCallback(name, service, this).isOk()) { - ALOGE("Failed to add client callback for service %s", name.c_str()); - return false; - } - if (!reRegister) { + if (!manager->registerClientCallback(name, service, this).isOk()) { + ALOGE("Failed to add client callback for service %s", name.c_str()); + return false; + } + // Only add this when a service is added for the first time, as it is not removed mRegisteredServices[name] = {service, allowIsolated, dumpFlags}; } -- cgit v1.2.3-59-g8ed1b From e06ad2bd7d0cb8eacc256cf987e16b0298c92fd9 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 10 Apr 2020 15:09:33 -0700 Subject: SurfaceComposerClient: Document BufferCache There were some questions about how this worked after some recent bug-fixes. Taking a chance to document while its fresh. Bug: 153561718 Test: Comments only Change-Id: I06d12be283ffeb9818daabfb7e4b12b64c1ac544 --- libs/gui/SurfaceComposerClient.cpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 605c2e8848..d9cbeb71d2 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -241,8 +241,31 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener // --------------------------------------------------------------------------- -void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId); - +void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId); + +/** + * We use the BufferCache to reduce the overhead of exchanging GraphicBuffers with + * the server. If we were to simply parcel the GraphicBuffer we would pay two overheads + * 1. Cost of sending the FD + * 2. Cost of importing the GraphicBuffer with the mapper in the receiving process. + * To ease this cost we implement the following scheme of caching buffers to integers, + * or said-otherwise, naming them with integers. This is the scheme known as slots in + * the legacy BufferQueue system. + * 1. When sending Buffers to SurfaceFlinger we look up the Buffer in the cache. + * 2. If there is a cache-hit we remove the Buffer from the Transaction and instead + * send the cached integer. + * 3. If there is a cache miss, we cache the new buffer and send the integer + * along with the Buffer, SurfaceFlinger on it's side creates a new cache + * entry, and we use the integer for further communication. + * A few details about lifetime: + * 1. The cache evicts by LRU. The server side cache is keyed by BufferCache::getToken + * which is per process Unique. The server side cache is larger than the client side + * cache so that the server will never evict entries before the client. + * 2. When the client evicts an entry it notifies the server via an uncacheBuffer + * transaction. + * 3. The client only references the Buffers by ID, and uses buffer->addDeathCallback + * to auto-evict destroyed buffers. + */ class BufferCache : public Singleton { public: BufferCache() : token(new BBinder()) {} @@ -270,7 +293,7 @@ public: evictLeastRecentlyUsedBuffer(); } - buffer->addDeathCallback(bufferCacheCallback, nullptr); + buffer->addDeathCallback(removeDeadBufferCallback, nullptr); mBuffers[buffer->getId()] = getCounter(); return buffer->getId(); @@ -318,7 +341,7 @@ private: ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache); -void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId) { +void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId) { // GraphicBuffer id's are used as the cache ids. BufferCache::getInstance().uncache(graphicBufferId); } @@ -576,9 +599,11 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { uint64_t cacheId = 0; status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId); if (ret == NO_ERROR) { + // Cache-hit. Strip the buffer and send only the id. s->what &= ~static_cast(layer_state_t::eBufferChanged); s->buffer = nullptr; } else { + // Cache-miss. Include the buffer and send the new cacheId. cacheId = BufferCache::getInstance().cache(s->buffer); } s->what |= layer_state_t::eCachedBufferChanged; -- cgit v1.2.3-59-g8ed1b From 470df5f0d6a272fd0c92f5967e43af0f29a5c866 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 2 Apr 2020 22:27:42 -0700 Subject: SF: Fix thread safety in ISurfaceComposer APIs Fix a few cases of ISurfaceComposer functions looking up displays and calling into HWC without holding mStateLock. Clean up error handling for consistent messages and accurate status codes. Bug: 123715322 Test: Boot (no repro, just an audit) Change-Id: I6432e15c4166b27398137b681b4ea7c056fea5e4 --- libs/gui/ISurfaceComposer.cpp | 5 +- libs/gui/include/gui/ISurfaceComposer.h | 5 +- libs/gui/tests/Surface_test.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 235 ++++++++++----------- services/surfaceflinger/SurfaceFlinger.h | 26 +-- .../tests/unittests/DisplayTransactionTest.cpp | 3 +- 6 files changed, 130 insertions(+), 148 deletions(-) (limited to 'libs') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index bd4d62c4f7..6fd53cf47a 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -795,8 +795,7 @@ public: } virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, - uint8_t componentMask, - uint64_t maxFrames) const { + uint8_t componentMask, uint64_t maxFrames) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -1038,7 +1037,7 @@ public: return NO_ERROR; } - virtual status_t setDisplayBrightness(const sp& displayToken, float brightness) const { + virtual status_t setDisplayBrightness(const sp& displayToken, float brightness) { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 3cef25639f..b4a3fbec2a 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -383,7 +383,7 @@ public: */ virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, uint8_t componentMask, - uint64_t maxFrames) const = 0; + uint64_t maxFrames) = 0; /* Returns statistics on the color profile of the last frame displayed for a given display * @@ -468,8 +468,7 @@ public: * BAD_VALUE if the brightness is invalid, or * INVALID_OPERATION if brightness operations are not supported. */ - virtual status_t setDisplayBrightness(const sp& displayToken, - float brightness) const = 0; + virtual status_t setDisplayBrightness(const sp& displayToken, float brightness) = 0; /* * Sends a power hint to the composer. This function is asynchronous. diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ef1fd026f2..2de6b69659 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -804,7 +804,7 @@ public: } status_t setDisplayContentSamplingEnabled(const sp& /*display*/, bool /*enable*/, uint8_t /*componentMask*/, - uint64_t /*maxFrames*/) const override { + uint64_t /*maxFrames*/) override { return NO_ERROR; } status_t getDisplayedContentSample(const sp& /*display*/, uint64_t /*maxFrames*/, @@ -822,7 +822,7 @@ public: return NO_ERROR; } status_t setDisplayBrightness(const sp& /*displayToken*/, - float /*brightness*/) const override { + float /*brightness*/) override { return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29793228f8..cd78c1a147 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -466,17 +466,17 @@ sp SurfaceFlinger::createDisplay(const String8& displayName, } void SurfaceFlinger::destroyDisplay(const sp& displayToken) { - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); - ssize_t index = mCurrentState.displays.indexOfKey(displayToken); + const ssize_t index = mCurrentState.displays.indexOfKey(displayToken); if (index < 0) { - ALOGE("destroyDisplay: Invalid display token %p", displayToken.get()); + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); return; } const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); - if (!state.isVirtual()) { - ALOGE("destroyDisplay called for non-virtual display"); + if (state.physical) { + ALOGE("%s: Invalid operation on physical display", __FUNCTION__); return; } mInterceptor->saveDisplayDeletion(state.sequenceId); @@ -908,20 +908,29 @@ status_t SurfaceFlinger::getDisplayStats(const sp&, DisplayStatInfo* st } int SurfaceFlinger::getActiveConfig(const sp& displayToken) { - const auto display = getDisplayDevice(displayToken); - if (!display) { - ALOGE("getActiveConfig: Invalid display token %p", displayToken.get()); - return BAD_VALUE; + int activeConfig; + bool isPrimary; + + { + Mutex::Autolock lock(mStateLock); + + if (const auto display = getDisplayDeviceLocked(displayToken)) { + activeConfig = display->getActiveConfig().value(); + isPrimary = display->isPrimary(); + } else { + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + return NAME_NOT_FOUND; + } } - if (display->isPrimary()) { + if (isPrimary) { std::lock_guard lock(mActiveConfigLock); if (mDesiredActiveConfigChanged) { return mDesiredActiveConfig.configId.value(); } } - return display->getActiveConfig().value(); + return activeConfig; } void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { @@ -972,17 +981,16 @@ status_t SurfaceFlinger::setActiveConfig(const sp& displayToken, int mo return BAD_VALUE; } - status_t result = NO_ERROR; + status_t result = NAME_NOT_FOUND; postMessageSync(new LambdaMessage([&]() { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set allowed display configs for invalid display token %p", displayToken.get()); - result = BAD_VALUE; } else if (display->isVirtual()) { ALOGW("Attempt to set allowed display configs for virtual display"); - result = BAD_VALUE; + result = INVALID_OPERATION; } else { HwcConfigIndexType config(mode); const auto& refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(config); @@ -1161,7 +1169,7 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp& displayTok // Currently we only support this API for a single internal display. if (getInternalDisplayToken() != displayToken) { - return BAD_VALUE; + return NAME_NOT_FOUND; } memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries)); @@ -1169,7 +1177,9 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp& displayTok } ColorMode SurfaceFlinger::getActiveColorMode(const sp& displayToken) { - if (const auto display = getDisplayDevice(displayToken)) { + Mutex::Autolock lock(mStateLock); + + if (const auto display = getDisplayDeviceLocked(displayToken)) { return display->getCompositionDisplay()->getState().colorMode; } return static_cast(BAD_VALUE); @@ -1185,7 +1195,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col decodeColorMode(mode).c_str(), mode, displayToken.get()); return; } - const auto display = getDisplayDevice(displayToken); + const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); @@ -1205,16 +1215,14 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, Col status_t SurfaceFlinger::getAutoLowLatencyModeSupport(const sp& displayToken, bool* outSupport) const { - Mutex::Autolock _l(mStateLock); - if (!displayToken) { - ALOGE("getAutoLowLatencyModeSupport() failed. Missing display token."); return BAD_VALUE; } + + Mutex::Autolock lock(mStateLock); + const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { - ALOGE("getAutoLowLatencyModeSupport() failed. Display id for display token %p not found.", - displayToken.get()); return NAME_NOT_FOUND; } *outSupport = getHwComposer().hasDisplayCapability(*displayId, @@ -1223,64 +1231,45 @@ status_t SurfaceFlinger::getAutoLowLatencyModeSupport(const sp& display } void SurfaceFlinger::setAutoLowLatencyMode(const sp& displayToken, bool on) { - postMessageAsync(new LambdaMessage([=] { setAutoLowLatencyModeInternal(displayToken, on); })); -} - -void SurfaceFlinger::setAutoLowLatencyModeInternal(const sp& displayToken, bool on) { - if (!displayToken) { - ALOGE("setAutoLowLatencyMode() failed. Missing display token."); - return; - } - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("setAutoLowLatencyMode() failed. Display id for display token %p not found.", - displayToken.get()); - return; - } - - getHwComposer().setAutoLowLatencyMode(*displayId, on); + postMessageAsync(new LambdaMessage([=] { + if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { + getHwComposer().setAutoLowLatencyMode(*displayId, on); + } else { + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + } + })); } status_t SurfaceFlinger::getGameContentTypeSupport(const sp& displayToken, bool* outSupport) const { - Mutex::Autolock _l(mStateLock); - if (!displayToken) { - ALOGE("getGameContentTypeSupport() failed. Missing display token."); return BAD_VALUE; } + + Mutex::Autolock lock(mStateLock); + const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { - ALOGE("getGameContentTypeSupport() failed. Display id for display token %p not found.", - displayToken.get()); return NAME_NOT_FOUND; } - std::vector outSupportedContentTypes; - getHwComposer().getSupportedContentTypes(*displayId, &outSupportedContentTypes); - *outSupport = std::find(outSupportedContentTypes.begin(), outSupportedContentTypes.end(), - HWC2::ContentType::Game) != outSupportedContentTypes.end(); + std::vector types; + getHwComposer().getSupportedContentTypes(*displayId, &types); + + *outSupport = std::any_of(types.begin(), types.end(), + [](auto type) { return type == HWC2::ContentType::Game; }); return NO_ERROR; } void SurfaceFlinger::setGameContentType(const sp& displayToken, bool on) { - postMessageAsync(new LambdaMessage([=] { setGameContentTypeInternal(displayToken, on); })); -} - -void SurfaceFlinger::setGameContentTypeInternal(const sp& displayToken, bool on) { - if (!displayToken) { - ALOGE("setGameContentType() failed. Missing display token."); - return; - } - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("setGameContentType() failed. Display id for display token %p not found.", - displayToken.get()); - return; - } - - const HWC2::ContentType type = on ? HWC2::ContentType::Game : HWC2::ContentType::None; - getHwComposer().setContentType(*displayId, type); + postMessageAsync(new LambdaMessage([=] { + if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { + const auto type = on ? HWC2::ContentType::Game : HWC2::ContentType::None; + getHwComposer().setContentType(*displayId, type); + } else { + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + } + })); } status_t SurfaceFlinger::clearAnimationFrameStats() { @@ -1297,15 +1286,15 @@ status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { status_t SurfaceFlinger::getHdrCapabilities(const sp& displayToken, HdrCapabilities* outCapabilities) const { - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); const auto display = getDisplayDeviceLocked(displayToken); if (!display) { - ALOGE("getHdrCapabilities: Invalid display token %p", displayToken.get()); - return BAD_VALUE; + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + return NAME_NOT_FOUND; } - // At this point the DisplayDeivce should already be set up, + // At this point the DisplayDevice should already be set up, // meaning the luminance information is already queried from // hardware composer and stored properly. const HdrCapabilities& capabilities = display->getHdrCapabilities(); @@ -1348,39 +1337,46 @@ status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp if (!outFormat || !outDataspace || !outComponentMask) { return BAD_VALUE; } - const auto display = getDisplayDevice(displayToken); - if (!display || !display->getId()) { - ALOGE("getDisplayedContentSamplingAttributes: Bad display token: %p", display.get()); - return BAD_VALUE; + + Mutex::Autolock lock(mStateLock); + + const auto displayId = getPhysicalDisplayIdLocked(displayToken); + if (!displayId) { + return NAME_NOT_FOUND; } - return getHwComposer().getDisplayedContentSamplingAttributes(*display->getId(), outFormat, + + return getHwComposer().getDisplayedContentSamplingAttributes(*displayId, outFormat, outDataspace, outComponentMask); } status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp& displayToken, bool enable, uint8_t componentMask, - uint64_t maxFrames) const { - const auto display = getDisplayDevice(displayToken); - if (!display || !display->getId()) { - ALOGE("setDisplayContentSamplingEnabled: Bad display token: %p", display.get()); - return BAD_VALUE; - } + uint64_t maxFrames) { + status_t result = NAME_NOT_FOUND; - return getHwComposer().setDisplayContentSamplingEnabled(*display->getId(), enable, - componentMask, maxFrames); + postMessageSync(new LambdaMessage([&] { + if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { + result = getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable, + componentMask, maxFrames); + } else { + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + } + })); + + return result; } status_t SurfaceFlinger::getDisplayedContentSample(const sp& displayToken, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) const { - const auto display = getDisplayDevice(displayToken); - if (!display || !display->getId()) { - ALOGE("getDisplayContentSample: Bad display token: %p", displayToken.get()); - return BAD_VALUE; + Mutex::Autolock lock(mStateLock); + + const auto displayId = getPhysicalDisplayIdLocked(displayToken); + if (!displayId) { + return NAME_NOT_FOUND; } - return getHwComposer().getDisplayedContentSample(*display->getId(), maxFrames, timestamp, - outStats); + return getHwComposer().getDisplayedContentSample(*displayId, maxFrames, timestamp, outStats); } status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const { @@ -1396,19 +1392,15 @@ status_t SurfaceFlinger::isWideColorDisplay(const sp& displayToken, if (!displayToken || !outIsWideColorDisplay) { return BAD_VALUE; } - Mutex::Autolock _l(mStateLock); + + Mutex::Autolock lock(mStateLock); const auto display = getDisplayDeviceLocked(displayToken); if (!display) { - return BAD_VALUE; + return NAME_NOT_FOUND; } - // Use hasWideColorDisplay to override built-in display. - const auto displayId = display->getId(); - if (displayId && displayId == getInternalDisplayIdLocked()) { - *outIsWideColorDisplay = hasWideColorDisplay; - return NO_ERROR; - } - *outIsWideColorDisplay = display->hasWideColorGamut(); + *outIsWideColorDisplay = + display->isPrimary() ? hasWideColorDisplay : display->hasWideColorGamut(); return NO_ERROR; } @@ -1483,6 +1475,9 @@ status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp& displayT if (!displayToken || !outSupport) { return BAD_VALUE; } + + Mutex::Autolock lock(mStateLock); + const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { return NAME_NOT_FOUND; @@ -1492,16 +1487,22 @@ status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp& displayT return NO_ERROR; } -status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, - float brightness) const { +status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, float brightness) { if (!displayToken) { return BAD_VALUE; } - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - return NAME_NOT_FOUND; - } - return getHwComposer().setDisplayBrightness(*displayId, brightness); + + status_t result = NAME_NOT_FOUND; + + postMessageSync(new LambdaMessage([&] { + if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { + result = getHwComposer().setDisplayBrightness(*displayId, brightness); + } else { + ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + } + })); + + return result; } status_t SurfaceFlinger::notifyPowerHint(int32_t hintId) { @@ -4230,7 +4231,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, int void SurfaceFlinger::setPowerMode(const sp& displayToken, int mode) { postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS { - const auto display = getDisplayDevice(displayToken); + const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set power mode %d for invalid display token %p", mode, displayToken.get()); @@ -5343,10 +5344,10 @@ status_t SurfaceFlinger::captureScreen(const sp& displayToken, sp display; { - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); display = getDisplayDeviceLocked(displayToken); - if (!display) return BAD_VALUE; + if (!display) return NAME_NOT_FOUND; // set the requested width/height to the logical display viewport size // by default @@ -5422,10 +5423,10 @@ status_t SurfaceFlinger::captureScreen(uint64_t displayOrLayerStack, Dataspace* uint32_t height; ui::Transform::RotationFlags captureOrientation; { - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); display = getDisplayByIdOrLayerStack(displayOrLayerStack); if (!display) { - return BAD_VALUE; + return NAME_NOT_FOUND; } width = uint32_t(display->getViewport().width()); @@ -5560,7 +5561,7 @@ status_t SurfaceFlinger::captureLayers( std::unordered_set, ISurfaceComposer::SpHash> excludeLayers; Rect displayViewport; { - Mutex::Autolock _l(mStateLock); + Mutex::Autolock lock(mStateLock); parent = fromHandle(layerHandleBinder); if (parent == nullptr || parent->isRemovedFromCurrentState()) { @@ -5604,9 +5605,9 @@ status_t SurfaceFlinger::captureLayers( } } - auto display = getDisplayByLayerStack(parent->getLayerStack()); + const auto display = getDisplayByLayerStack(parent->getLayerStack()); if (!display) { - return BAD_VALUE; + return NAME_NOT_FOUND; } displayViewport = display->getViewport(); @@ -5989,17 +5990,16 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp& display return BAD_VALUE; } - status_t result = NO_ERROR; + status_t result = NAME_NOT_FOUND; postMessageSync(new LambdaMessage([&]() { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { - result = BAD_VALUE; ALOGE("Attempt to set desired display configs for invalid display token %p", displayToken.get()); } else if (display->isVirtual()) { - result = BAD_VALUE; ALOGW("Attempt to set desired display configs for virtual display"); + result = INVALID_OPERATION; } else { result = setDesiredDisplayConfigSpecsInternal(display, scheduler::RefreshRateConfigs:: @@ -6038,12 +6038,11 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp& display *outMaxRefreshRate = policy.maxRefreshRate; return NO_ERROR; } else if (display->isVirtual()) { - return BAD_VALUE; + return INVALID_OPERATION; } else { const auto displayId = display->getId(); - if (!displayId) { - return BAD_VALUE; - } + LOG_FATAL_IF(!displayId); + *outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId); auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod(); *outMinRefreshRate = 1e9f / vsyncPeriod; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 12efca1873..72d1ffee9d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -475,14 +475,13 @@ private: status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, ui::Dataspace* outWideColorGamutDataspace, ui::PixelFormat* outWideColorGamutPixelFormat) const override; - status_t getDisplayedContentSamplingAttributes(const sp& display, + status_t getDisplayedContentSamplingAttributes(const sp& displayToken, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) const override; - status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, - uint8_t componentMask, - uint64_t maxFrames) const override; - status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + status_t setDisplayContentSamplingEnabled(const sp& displayToken, bool enable, + uint8_t componentMask, uint64_t maxFrames) override; + status_t getDisplayedContentSample(const sp& displayToken, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) const override; status_t getProtectedContentSupport(bool* outSupported) const override; @@ -498,7 +497,7 @@ private: float* outMaxRefreshRate) override; status_t getDisplayBrightnessSupport(const sp& displayToken, bool* outSupport) const override; - status_t setDisplayBrightness(const sp& displayToken, float brightness) const override; + status_t setDisplayBrightness(const sp& displayToken, float brightness) override; status_t notifyPowerHint(int32_t hintId) override; status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) override; @@ -581,11 +580,6 @@ private: const std::optional& policy, bool overridePolicy) EXCLUDES(mStateLock); - // called on the main thread in response to setAutoLowLatencyMode() - void setAutoLowLatencyModeInternal(const sp& displayToken, bool on); - // called on the main thread in response to setGameContentType() - void setGameContentTypeInternal(const sp& displayToken, bool on); - // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -740,16 +734,6 @@ private: // called when starting, or restarting after system_server death void initializeDisplays(); - sp getDisplayDevice(const wp& displayToken) const { - Mutex::Autolock _l(mStateLock); - return getDisplayDeviceLocked(displayToken); - } - - sp getDisplayDevice(const wp& displayToken) { - Mutex::Autolock _l(mStateLock); - return getDisplayDeviceLocked(displayToken); - } - // NOTE: can only be called from the main thread or with mStateLock held sp getDisplayDeviceLocked(const wp& displayToken) const { return const_cast(this)->getDisplayDeviceLocked(displayToken); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index ea3d744930..cd114098b1 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1731,7 +1731,8 @@ TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) { ui::DisplayPrimaries primaries; populateDummyDisplayNativePrimaries(primaries); - EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries)); + EXPECT_EQ(NAME_NOT_FOUND, + mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries)); // Check primaries argument wasn't modified in case of failure checkDummyDisplayNativePrimaries(primaries); -- cgit v1.2.3-59-g8ed1b From dac1acbcf7c3372c29ab4ac62334036d8e26fc92 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Mon, 6 Apr 2020 16:11:25 +0200 Subject: [RESTRICT AUTOMERGE] Add relative address to DeviceProductInfo. This CL adds a field relativeAddress to DeviceProductInfo so it can be surfaced in the framework. For HDMI connections the field is populated with the physical address. Bug: 147994746 Test: atest DisplayIdentificationTest Change-Id: I2711407aa1be079df8086e233ee3f0cf90ba1741 --- libs/ui/include/ui/DeviceProductInfo.h | 9 ++++++ .../DisplayHardware/DisplayIdentification.cpp | 6 ++++ .../DisplayHardware/DisplayIdentification.h | 2 +- .../tests/unittests/DisplayIdentificationTest.cpp | 34 ++++++++++++---------- 4 files changed, 35 insertions(+), 16 deletions(-) (limited to 'libs') diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h index c396e738b9..af00342c0c 100644 --- a/libs/ui/include/ui/DeviceProductInfo.h +++ b/libs/ui/include/ui/DeviceProductInfo.h @@ -31,6 +31,10 @@ using PnpId = std::array; // product information about the intermediate device. struct DeviceProductInfo { static constexpr size_t TEXT_BUFFER_SIZE = 20; + static constexpr size_t RELATIVE_ADDRESS_SIZE = 4; + + using RelativeAddress = std::array; + static constexpr RelativeAddress NO_RELATIVE_ADDRESS = {0xff, 0xff, 0xff, 0xff}; struct ModelYear { uint32_t year; @@ -54,6 +58,11 @@ struct DeviceProductInfo { using ManufactureOrModelDate = std::variant; ManufactureOrModelDate manufactureOrModelDate; + + // Relative address in the display network. Unavailable address is indicated + // by all elements equal to 255. + // For example, for HDMI connected device this will be the physical address. + RelativeAddress relativeAddress; }; } // namespace android diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp index b6d904f9f9..4dfc7431de 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp @@ -96,6 +96,12 @@ DeviceProductInfo buildDeviceProductInfo(const Edid& edid) { info.manufactureOrModelDate = date; } + if (edid.cea861Block && edid.cea861Block->hdmiVendorDataBlock) { + const auto& address = edid.cea861Block->hdmiVendorDataBlock->physicalAddress; + info.relativeAddress = {address.a, address.b, address.c, address.d}; + } else { + info.relativeAddress = DeviceProductInfo::NO_RELATIVE_ADDRESS; + } return info; } diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h index fc2f72e80c..9e6c549f03 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h @@ -70,7 +70,7 @@ struct HdmiPhysicalAddress { }; struct HdmiVendorDataBlock { - std::optional physicalAddress; + HdmiPhysicalAddress physicalAddress; }; struct Cea861ExtensionBlock : ExtensionBlock { diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp index cc11aa9594..2a0e913e7a 100644 --- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp @@ -209,12 +209,11 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(41, edid->manufactureWeek); ASSERT_TRUE(edid->cea861Block); ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock); - ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress); auto physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress; - EXPECT_EQ(2, physicalAddress->a); - EXPECT_EQ(0, physicalAddress->b); - EXPECT_EQ(0, physicalAddress->c); - EXPECT_EQ(0, physicalAddress->d); + EXPECT_EQ(2, physicalAddress.a); + EXPECT_EQ(0, physicalAddress.b); + EXPECT_EQ(0, physicalAddress.c); + EXPECT_EQ(0, physicalAddress.d); edid = parseEdid(getPanasonicTvEdid()); ASSERT_TRUE(edid); @@ -227,12 +226,11 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(0, edid->manufactureWeek); ASSERT_TRUE(edid->cea861Block); ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock); - ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress); physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress; - EXPECT_EQ(2, physicalAddress->a); - EXPECT_EQ(0, physicalAddress->b); - EXPECT_EQ(0, physicalAddress->c); - EXPECT_EQ(0, physicalAddress->d); + EXPECT_EQ(2, physicalAddress.a); + EXPECT_EQ(0, physicalAddress.b); + EXPECT_EQ(0, physicalAddress.c); + EXPECT_EQ(0, physicalAddress.d); edid = parseEdid(getHisenseTvEdid()); ASSERT_TRUE(edid); @@ -245,12 +243,11 @@ TEST(DisplayIdentificationTest, parseEdid) { EXPECT_EQ(18, edid->manufactureWeek); ASSERT_TRUE(edid->cea861Block); ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock); - ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock->physicalAddress); physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress; - EXPECT_EQ(1, physicalAddress->a); - EXPECT_EQ(2, physicalAddress->b); - EXPECT_EQ(3, physicalAddress->c); - EXPECT_EQ(4, physicalAddress->d); + EXPECT_EQ(1, physicalAddress.a); + EXPECT_EQ(2, physicalAddress.b); + EXPECT_EQ(3, physicalAddress.c); + EXPECT_EQ(4, physicalAddress.d); edid = parseEdid(getCtlDisplayEdid()); ASSERT_TRUE(edid); @@ -315,6 +312,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { using ManufactureYear = DeviceProductInfo::ManufactureYear; using ManufactureWeekAndYear = DeviceProductInfo::ManufactureWeekAndYear; using ModelYear = DeviceProductInfo::ModelYear; + using RelativeAddress = DeviceProductInfo::RelativeAddress; { const auto displayIdInfo = parseDisplayIdentificationData(0, getInternalEdid()); @@ -326,6 +324,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { EXPECT_STREQ("12610", info.productId.data()); ASSERT_TRUE(std::holds_alternative(info.manufactureOrModelDate)); EXPECT_EQ(2011, std::get(info.manufactureOrModelDate).year); + EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress); } { const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEdid()); @@ -339,6 +338,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { const auto& date = std::get(info.manufactureOrModelDate); EXPECT_EQ(2012, date.year); EXPECT_EQ(2, date.week); + EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress); } { const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEedid()); @@ -352,6 +352,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { const auto& date = std::get(info.manufactureOrModelDate); EXPECT_EQ(2011, date.year); EXPECT_EQ(41, date.week); + EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress); } { const auto displayIdInfo = parseDisplayIdentificationData(0, getPanasonicTvEdid()); @@ -364,6 +365,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { ASSERT_TRUE(std::holds_alternative(info.manufactureOrModelDate)); const auto& date = std::get(info.manufactureOrModelDate); EXPECT_EQ(2019, date.year); + EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress); } { const auto displayIdInfo = parseDisplayIdentificationData(0, getHisenseTvEdid()); @@ -377,6 +379,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { const auto& date = std::get(info.manufactureOrModelDate); EXPECT_EQ(2019, date.year); EXPECT_EQ(18, date.week); + EXPECT_EQ((RelativeAddress{{1, 2, 3, 4}}), info.relativeAddress); } { const auto displayIdInfo = parseDisplayIdentificationData(0, getCtlDisplayEdid()); @@ -388,6 +391,7 @@ TEST(DisplayIdentificationTest, deviceProductInfo) { EXPECT_STREQ("9373", info.productId.data()); ASSERT_TRUE(std::holds_alternative(info.manufactureOrModelDate)); EXPECT_EQ(2013, std::get(info.manufactureOrModelDate).year); + EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress); } } -- cgit v1.2.3-59-g8ed1b From d0d6ccd726a2dd70c4df080e32d1e89d9e3f8640 Mon Sep 17 00:00:00 2001 From: Jiwen 'Steve' Cai Date: Mon, 13 Apr 2020 18:57:54 -0700 Subject: Remove binder-based BufferHub from libui We are removing Binder-based BufferHub from Android. Please refer to b/147002762 for details. In short, those services and libraries were originally created as a major refactor for a future product line. As part of a strategy shift, these components are no longer needed. Bug: 147002762 Test: Build and flash blueline Merged-In: If5e64880911f2271a297b1628079261a4251f9e3 Change-Id: I9f7ac210b23b774d44c8fa85401f0aaf690c66e5 --- libs/gui/BufferHubProducer.cpp | 1 - libs/ui/Android.bp | 14 - libs/ui/BufferHubBuffer.cpp | 358 ---------------- libs/ui/BufferHubEventFd.cpp | 49 --- libs/ui/BufferHubMetadata.cpp | 104 ----- libs/ui/GraphicBuffer.cpp | 111 ----- libs/ui/include/ui/BufferHubBuffer.h | 144 ------- libs/ui/include/ui/BufferHubEventFd.h | 65 --- libs/ui/include/ui/BufferHubMetadata.h | 88 ---- libs/ui/include/ui/GraphicBuffer.h | 37 -- libs/ui/tests/Android.bp | 32 -- libs/ui/tests/BufferHubBuffer_test.cpp | 477 --------------------- libs/ui/tests/BufferHubEventFd_test.cpp | 428 ------------------ libs/ui/tests/BufferHubMetadata_test.cpp | 98 ----- libs/ui/tests/GraphicBufferOverBinder_test.cpp | 32 -- libs/ui/tests/GraphicBuffer_test.cpp | 86 ---- services/bufferhub/Android.bp | 77 ---- services/bufferhub/BufferClient.cpp | 100 ----- services/bufferhub/BufferHubIdGenerator.cpp | 59 --- services/bufferhub/BufferHubService.cpp | 401 ----------------- services/bufferhub/BufferNode.cpp | 113 ----- .../android.frameworks.bufferhub@1.0-service.rc | 6 - .../android.frameworks.bufferhub@1.0-service.xml | 11 - .../bufferhub/include/bufferhub/BufferClient.h | 75 ---- .../include/bufferhub/BufferHubIdGenerator.h | 61 --- .../bufferhub/include/bufferhub/BufferHubService.h | 92 ---- services/bufferhub/include/bufferhub/BufferNode.h | 100 ----- services/bufferhub/main_bufferhub.cpp | 37 -- services/bufferhub/tests/Android.bp | 26 -- .../bufferhub/tests/BufferHubIdGenerator_test.cpp | 48 --- services/bufferhub/tests/BufferNode_test.cpp | 109 ----- 31 files changed, 3439 deletions(-) delete mode 100644 libs/ui/BufferHubBuffer.cpp delete mode 100644 libs/ui/BufferHubEventFd.cpp delete mode 100644 libs/ui/BufferHubMetadata.cpp delete mode 100644 libs/ui/include/ui/BufferHubBuffer.h delete mode 100644 libs/ui/include/ui/BufferHubEventFd.h delete mode 100644 libs/ui/include/ui/BufferHubMetadata.h delete mode 100644 libs/ui/tests/BufferHubBuffer_test.cpp delete mode 100644 libs/ui/tests/BufferHubEventFd_test.cpp delete mode 100644 libs/ui/tests/BufferHubMetadata_test.cpp delete mode 100644 services/bufferhub/Android.bp delete mode 100644 services/bufferhub/BufferClient.cpp delete mode 100644 services/bufferhub/BufferHubIdGenerator.cpp delete mode 100644 services/bufferhub/BufferHubService.cpp delete mode 100644 services/bufferhub/BufferNode.cpp delete mode 100644 services/bufferhub/android.frameworks.bufferhub@1.0-service.rc delete mode 100644 services/bufferhub/android.frameworks.bufferhub@1.0-service.xml delete mode 100644 services/bufferhub/include/bufferhub/BufferClient.h delete mode 100644 services/bufferhub/include/bufferhub/BufferHubIdGenerator.h delete mode 100644 services/bufferhub/include/bufferhub/BufferHubService.h delete mode 100644 services/bufferhub/include/bufferhub/BufferNode.h delete mode 100644 services/bufferhub/main_bufferhub.cpp delete mode 100644 services/bufferhub/tests/Android.bp delete mode 100644 services/bufferhub/tests/BufferHubIdGenerator_test.cpp delete mode 100644 services/bufferhub/tests/BufferNode_test.cpp (limited to 'libs') diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp index 4be014fbb1..489f3c356b 100644 --- a/libs/gui/BufferHubProducer.cpp +++ b/libs/gui/BufferHubProducer.cpp @@ -19,7 +19,6 @@ #include #include #include -#include namespace android { diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index ba6255dcab..458ee675d8 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -36,9 +36,6 @@ cc_library_shared { srcs: [ "ColorSpace.cpp", - "BufferHubBuffer.cpp", - "BufferHubEventFd.cpp", - "BufferHubMetadata.cpp", "DebugUtils.cpp", "Fence.cpp", "FenceTime.cpp", @@ -72,7 +69,6 @@ cc_library_shared { //defaults: ["libui-validate-regions-defaults"], shared_libs: [ - "android.frameworks.bufferhub@1.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", "android.hardware.graphics.allocator@4.0", @@ -109,30 +105,20 @@ cc_library_shared { vendor: { cflags: ["-DLIBUI_IN_VNDK"], exclude_srcs: [ - "BufferHubBuffer.cpp", - "BufferHubEventFd.cpp", - "BufferHubMetadata.cpp", ], exclude_header_libs: [ - "libbufferhub_headers", - "libdvr_headers", ], exclude_shared_libs: [ - "android.frameworks.bufferhub@1.0", - "libpdx_default_transport", ], }, }, header_libs: [ "libbase_headers", - "libbufferhub_headers", - "libdvr_headers", "libnativebase_headers", "libnativewindow_headers", "libhardware_headers", "libui_headers", - "libpdx_headers", ], export_static_lib_headers: [ diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp deleted file mode 100644 index 1dfc1e9e88..0000000000 --- a/libs/ui/BufferHubBuffer.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "BufferHubBuffer" -#include - -#include -#include -#include -#include -#include -#include - -using ::android::base::unique_fd; -using ::android::BufferHubDefs::isAnyClientAcquired; -using ::android::BufferHubDefs::isAnyClientGained; -using ::android::BufferHubDefs::isClientAcquired; -using ::android::BufferHubDefs::isClientGained; -using ::android::BufferHubDefs::isClientPosted; -using ::android::BufferHubDefs::isClientReleased; -using ::android::frameworks::bufferhub::V1_0::BufferHubStatus; -using ::android::frameworks::bufferhub::V1_0::BufferTraits; -using ::android::frameworks::bufferhub::V1_0::IBufferClient; -using ::android::frameworks::bufferhub::V1_0::IBufferHub; -using ::android::hardware::hidl_handle; -using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription; - -namespace android { - -std::unique_ptr BufferHubBuffer::create(uint32_t width, uint32_t height, - uint32_t layerCount, uint32_t format, - uint64_t usage, size_t userMetadataSize) { - auto buffer = std::unique_ptr( - new BufferHubBuffer(width, height, layerCount, format, usage, userMetadataSize)); - return buffer->isValid() ? std::move(buffer) : nullptr; -} - -std::unique_ptr BufferHubBuffer::import(const sp& token) { - if (token == nullptr || token.get() == nullptr) { - ALOGE("%s: token cannot be nullptr!", __FUNCTION__); - return nullptr; - } - - auto buffer = std::unique_ptr(new BufferHubBuffer(token)); - return buffer->isValid() ? std::move(buffer) : nullptr; -} - -BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, - uint32_t format, uint64_t usage, size_t userMetadataSize) { - ATRACE_CALL(); - ALOGD("%s: width=%u height=%u layerCount=%u, format=%u " - "usage=%" PRIx64 " mUserMetadataSize=%zu", - __FUNCTION__, width, height, layerCount, format, usage, userMetadataSize); - - sp bufferhub = IBufferHub::getService(); - if (bufferhub.get() == nullptr) { - ALOGE("%s: BufferHub service not found!", __FUNCTION__); - return; - } - - AHardwareBuffer_Desc aDesc = {width, height, layerCount, format, - usage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL}; - HardwareBufferDescription desc; - memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription)); - - BufferHubStatus ret; - sp client; - BufferTraits bufferTraits; - IBufferHub::allocateBuffer_cb allocCb = [&](const auto& status, const auto& outClient, - const auto& outTraits) { - ret = status; - client = std::move(outClient); - bufferTraits = std::move(outTraits); - }; - - if (!bufferhub->allocateBuffer(desc, static_cast(userMetadataSize), allocCb).isOk()) { - ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__); - return; - } else if (ret != BufferHubStatus::NO_ERROR) { - ALOGE("%s: allocateBuffer failed with error %u.", __FUNCTION__, ret); - return; - } else if (client == nullptr) { - ALOGE("%s: allocateBuffer got null BufferClient.", __FUNCTION__); - return; - } - - const int importRet = initWithBufferTraits(bufferTraits); - if (importRet < 0) { - ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet)); - client->close(); - } - mBufferClient = std::move(client); -} - -BufferHubBuffer::BufferHubBuffer(const sp& token) { - sp bufferhub = IBufferHub::getService(); - if (bufferhub.get() == nullptr) { - ALOGE("%s: BufferHub service not found!", __FUNCTION__); - return; - } - - BufferHubStatus ret; - sp client; - BufferTraits bufferTraits; - IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient, - const auto& outTraits) { - ret = status; - client = std::move(outClient); - bufferTraits = std::move(outTraits); - }; - - // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership - // transfer. - if (!bufferhub->importBuffer(hidl_handle(token.get()->handle()), importCb).isOk()) { - ALOGE("%s: importBuffer transaction failed!", __FUNCTION__); - return; - } else if (ret != BufferHubStatus::NO_ERROR) { - ALOGE("%s: importBuffer failed with error %u.", __FUNCTION__, ret); - return; - } else if (client == nullptr) { - ALOGE("%s: importBuffer got null BufferClient.", __FUNCTION__); - return; - } - - const int importRet = initWithBufferTraits(bufferTraits); - if (importRet < 0) { - ALOGE("%s: Failed to import buffer: %s", __FUNCTION__, strerror(-importRet)); - client->close(); - } - mBufferClient = std::move(client); -} - -BufferHubBuffer::~BufferHubBuffer() { - // Close buffer client to avoid possible race condition: user could first duplicate and hold - // token with the original buffer gone, and then try to import the token. The close function - // will explicitly invalidate the token to avoid this. - if (mBufferClient != nullptr) { - if (!mBufferClient->close().isOk()) { - ALOGE("%s: close BufferClient transaction failed!", __FUNCTION__); - } - } -} - -int BufferHubBuffer::initWithBufferTraits(const BufferTraits& bufferTraits) { - ATRACE_CALL(); - - if (bufferTraits.bufferInfo.getNativeHandle() == nullptr) { - ALOGE("%s: missing buffer info handle.", __FUNCTION__); - return -EINVAL; - } - - if (bufferTraits.bufferHandle.getNativeHandle() == nullptr) { - ALOGE("%s: missing gralloc handle.", __FUNCTION__); - return -EINVAL; - } - - // Import fds. Dup fds because hidl_handle owns the fds. - unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0)); - mMetadata = BufferHubMetadata::import(std::move(ashmemFd)); - if (!mMetadata.isValid()) { - ALOGE("%s: Received an invalid metadata.", __FUNCTION__); - return -EINVAL; - } - - mEventFd = BufferHubEventFd(fcntl(bufferTraits.bufferInfo->data[1], F_DUPFD_CLOEXEC, 0)); - if (!mEventFd.isValid()) { - ALOGE("%s: Received ad invalid event fd.", __FUNCTION__); - return -EINVAL; - } - - int bufferId = bufferTraits.bufferInfo->data[2]; - if (bufferId < 0) { - ALOGE("%s: Received an invalid (negative) id.", __FUNCTION__); - return -EINVAL; - } - - uint32_t clientBitMask; - memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[3], sizeof(clientBitMask)); - if (clientBitMask == 0U) { - ALOGE("%s: Received an invalid client state mask.", __FUNCTION__); - return -EINVAL; - } - - uint32_t userMetadataSize; - memcpy(&userMetadataSize, &bufferTraits.bufferInfo->data[4], sizeof(userMetadataSize)); - if (mMetadata.userMetadataSize() != userMetadataSize) { - ALOGE("%s: user metadata size not match: expected %u, actual %zu.", __FUNCTION__, - userMetadataSize, mMetadata.userMetadataSize()); - return -EINVAL; - } - - size_t metadataSize = static_cast(mMetadata.metadataSize()); - if (metadataSize < BufferHubDefs::kMetadataHeaderSize) { - ALOGE("%s: metadata too small: %zu", __FUNCTION__, metadataSize); - return -EINVAL; - } - - // Populate shortcuts to the atomics in metadata. - auto metadataHeader = mMetadata.metadataHeader(); - mBufferState = &metadataHeader->bufferState; - mFenceState = &metadataHeader->fenceState; - mActiveClientsBitMask = &metadataHeader->activeClientsBitMask; - // The C++ standard recommends (but does not require) that lock-free atomic operations are - // also address-free, that is, suitable for communication between processes using shared - // memory. - LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(mBufferState) || - !std::atomic_is_lock_free(mFenceState) || - !std::atomic_is_lock_free(mActiveClientsBitMask), - "Atomic variables in ashmen are not lock free."); - - // Import the buffer: We only need to hold on the native_handle_t here so that - // GraphicBuffer instance can be created in future. - mBufferHandle = std::move(bufferTraits.bufferHandle); - memcpy(&mBufferDesc, &bufferTraits.bufferDesc, sizeof(AHardwareBuffer_Desc)); - - mId = bufferId; - mClientStateMask = clientBitMask; - - // TODO(b/112012161) Set up shared fences. - ALOGD("%s: id=%d, mBufferState=%" PRIx32 ".", __FUNCTION__, mId, - mBufferState->load(std::memory_order_acquire)); - return 0; -} - -int BufferHubBuffer::gain() { - uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire); - if (isClientGained(currentBufferState, mClientStateMask)) { - ALOGV("%s: Buffer is already gained by this client %" PRIx32 ".", __FUNCTION__, - mClientStateMask); - return 0; - } - do { - if (isAnyClientGained(currentBufferState & (~mClientStateMask)) || - isAnyClientAcquired(currentBufferState)) { - ALOGE("%s: Buffer is in use, id=%d mClientStateMask=%" PRIx32 " state=%" PRIx32 ".", - __FUNCTION__, mId, mClientStateMask, currentBufferState); - return -EBUSY; - } - // Change the buffer state to gained state, whose value happens to be the same as - // mClientStateMask. - } while (!mBufferState->compare_exchange_weak(currentBufferState, mClientStateMask, - std::memory_order_acq_rel, - std::memory_order_acquire)); - // TODO(b/119837586): Update fence state and return GPU fence. - return 0; -} - -int BufferHubBuffer::post() { - uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire); - uint32_t updatedBufferState = (~mClientStateMask) & BufferHubDefs::kHighBitsMask; - do { - if (!isClientGained(currentBufferState, mClientStateMask)) { - ALOGE("%s: Cannot post a buffer that is not gained by this client. buffer_id=%d " - "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".", - __FUNCTION__, mId, mClientStateMask, currentBufferState); - return -EBUSY; - } - // Set the producer client buffer state to released, other clients' buffer state to posted. - // Post to all existing and non-existing clients. - } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState, - std::memory_order_acq_rel, - std::memory_order_acquire)); - // TODO(b/119837586): Update fence state and return GPU fence if needed. - return 0; -} - -int BufferHubBuffer::acquire() { - uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire); - if (isClientAcquired(currentBufferState, mClientStateMask)) { - ALOGV("%s: Buffer is already acquired by this client %" PRIx32 ".", __FUNCTION__, - mClientStateMask); - return 0; - } - uint32_t updatedBufferState = 0U; - do { - if (!isClientPosted(currentBufferState, mClientStateMask)) { - ALOGE("%s: Cannot acquire a buffer that is not in posted state. buffer_id=%d " - "mClientStateMask=%" PRIx32 " state=%" PRIx32 ".", - __FUNCTION__, mId, mClientStateMask, currentBufferState); - return -EBUSY; - } - // Change the buffer state for this consumer from posted to acquired. - updatedBufferState = currentBufferState ^ mClientStateMask; - } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState, - std::memory_order_acq_rel, - std::memory_order_acquire)); - // TODO(b/119837586): Update fence state and return GPU fence. - return 0; -} - -int BufferHubBuffer::release() { - uint32_t currentBufferState = mBufferState->load(std::memory_order_acquire); - if (isClientReleased(currentBufferState, mClientStateMask)) { - ALOGV("%s: Buffer is already released by this client %" PRIx32 ".", __FUNCTION__, - mClientStateMask); - return 0; - } - uint32_t updatedBufferState = 0U; - do { - updatedBufferState = currentBufferState & (~mClientStateMask); - } while (!mBufferState->compare_exchange_weak(currentBufferState, updatedBufferState, - std::memory_order_acq_rel, - std::memory_order_acquire)); - // TODO(b/119837586): Update fence state and return GPU fence if needed. - return 0; -} - -bool BufferHubBuffer::isReleased() const { - return (mBufferState->load(std::memory_order_acquire) & - mActiveClientsBitMask->load(std::memory_order_acquire)) == 0; -} - -bool BufferHubBuffer::isValid() const { - return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U && - mEventFd.get() >= 0 && mMetadata.isValid() && mBufferClient != nullptr; -} - -sp BufferHubBuffer::duplicate() { - if (mBufferClient == nullptr) { - ALOGE("%s: missing BufferClient!", __FUNCTION__); - return nullptr; - } - - hidl_handle token; - BufferHubStatus ret; - IBufferClient::duplicate_cb dupCb = [&](const auto& outToken, const auto& status) { - token = std::move(outToken); - ret = status; - }; - - if (!mBufferClient->duplicate(dupCb).isOk()) { - ALOGE("%s: duplicate transaction failed!", __FUNCTION__); - return nullptr; - } else if (ret != BufferHubStatus::NO_ERROR) { - ALOGE("%s: duplicate failed with error %u.", __FUNCTION__, ret); - return nullptr; - } else if (token.getNativeHandle() == nullptr) { - ALOGE("%s: duplicate got null token.", __FUNCTION__); - return nullptr; - } - - return NativeHandle::create(native_handle_clone(token.getNativeHandle()), /*ownsHandle=*/true); -} - -} // namespace android diff --git a/libs/ui/BufferHubEventFd.cpp b/libs/ui/BufferHubEventFd.cpp deleted file mode 100644 index bffc2ca803..0000000000 --- a/libs/ui/BufferHubEventFd.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include - -namespace android { - -BufferHubEventFd::BufferHubEventFd() : mFd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)) {} - -BufferHubEventFd::BufferHubEventFd(int fd) : mFd(fd) {} - -status_t BufferHubEventFd::signal() const { - if (!isValid()) { - ALOGE("%s: cannot signal an invalid eventfd.", __FUNCTION__); - return DEAD_OBJECT; - } - - eventfd_write(mFd.get(), 1); - return OK; -} - -status_t BufferHubEventFd::clear() const { - if (!isValid()) { - ALOGE("%s: cannot clear an invalid eventfd.", __FUNCTION__); - return DEAD_OBJECT; - } - - eventfd_t value; - eventfd_read(mFd.get(), &value); - return OK; -} - -} // namespace android diff --git a/libs/ui/BufferHubMetadata.cpp b/libs/ui/BufferHubMetadata.cpp deleted file mode 100644 index 05bc7ddfbe..0000000000 --- a/libs/ui/BufferHubMetadata.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include -#include -#include - -namespace android { - -namespace { - -static const int kAshmemProt = PROT_READ | PROT_WRITE; - -} // namespace - -using BufferHubDefs::kMetadataHeaderSize; -using BufferHubDefs::MetadataHeader; - -/* static */ -BufferHubMetadata BufferHubMetadata::create(size_t userMetadataSize) { - // The size the of metadata buffer is used as the "width" parameter during allocation. Thus it - // cannot overflow uint32_t. - if (userMetadataSize >= (std::numeric_limits::max() - kMetadataHeaderSize)) { - ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", userMetadataSize); - return {}; - } - - const size_t metadataSize = userMetadataSize + kMetadataHeaderSize; - int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadataSize); - if (fd < 0) { - ALOGE("BufferHubMetadata::Create: failed to create ashmem region."); - return {}; - } - - // Hand over the ownership of the fd to a unique_fd immediately after the successful - // return of ashmem_create_region. The ashmemFd is going to own the fd and to prevent fd - // leaks during error handling. - unique_fd ashmemFd{fd}; - - if (ashmem_set_prot_region(ashmemFd.get(), kAshmemProt) != 0) { - ALOGE("BufferHubMetadata::Create: failed to set protect region."); - return {}; - } - - return BufferHubMetadata::import(std::move(ashmemFd)); -} - -/* static */ -BufferHubMetadata BufferHubMetadata::import(unique_fd ashmemFd) { - if (!ashmem_valid(ashmemFd.get())) { - ALOGE("BufferHubMetadata::Import: invalid ashmem fd."); - return {}; - } - - size_t metadataSize = static_cast(ashmem_get_size_region(ashmemFd.get())); - size_t userMetadataSize = metadataSize - kMetadataHeaderSize; - - // Note that here the buffer state is mapped from shared memory as an atomic object. The - // std::atomic's constructor will not be called so that the original value stored in the memory - // region can be preserved. - auto metadataHeader = static_cast(mmap(nullptr, metadataSize, kAshmemProt, - MAP_SHARED, ashmemFd.get(), - /*offset=*/0)); - if (metadataHeader == nullptr) { - ALOGE("BufferHubMetadata::Import: failed to map region."); - return {}; - } - - return BufferHubMetadata(userMetadataSize, std::move(ashmemFd), metadataHeader); -} - -BufferHubMetadata::BufferHubMetadata(size_t userMetadataSize, unique_fd ashmemFd, - MetadataHeader* metadataHeader) - : mUserMetadataSize(userMetadataSize), - mAshmemFd(std::move(ashmemFd)), - mMetadataHeader(metadataHeader) {} - -BufferHubMetadata::~BufferHubMetadata() { - if (mMetadataHeader != nullptr) { - int ret = munmap(mMetadataHeader, metadataSize()); - ALOGE_IF(ret != 0, - "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, error=%d.", errno); - mMetadataHeader = nullptr; - } -} - -} // namespace android diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 05fc590bac..3732fee7f2 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -23,10 +23,6 @@ #include -#ifndef LIBUI_IN_VNDK -#include -#endif // LIBUI_IN_VNDK - #include #include #include @@ -110,22 +106,6 @@ GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod m inUsage, inStride); } -#ifndef LIBUI_IN_VNDK -GraphicBuffer::GraphicBuffer(std::unique_ptr buffer) : GraphicBuffer() { - if (buffer == nullptr) { - mInitCheck = BAD_VALUE; - return; - } - - mInitCheck = initWithHandle(buffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE, - buffer->desc().width, buffer->desc().height, - static_cast(buffer->desc().format), - buffer->desc().layers, buffer->desc().usage, buffer->desc().stride); - mBufferId = buffer->id(); - mBufferHubBuffer = std::move(buffer); -} -#endif // LIBUI_IN_VNDK - GraphicBuffer::~GraphicBuffer() { ATRACE_CALL(); @@ -374,29 +354,14 @@ status_t GraphicBuffer::isSupported(uint32_t inWidth, uint32_t inHeight, PixelFo } size_t GraphicBuffer::getFlattenedSize() const { -#ifndef LIBUI_IN_VNDK - if (mBufferHubBuffer != nullptr) { - return 48; - } -#endif return static_cast(13 + (handle ? mTransportNumInts : 0)) * sizeof(int); } size_t GraphicBuffer::getFdCount() const { -#ifndef LIBUI_IN_VNDK - if (mBufferHubBuffer != nullptr) { - return 0; - } -#endif return static_cast(handle ? mTransportNumFds : 0); } status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const { -#ifndef LIBUI_IN_VNDK - if (mBufferHubBuffer != nullptr) { - return flattenBufferHubBuffer(buffer, size); - } -#endif size_t sizeNeeded = GraphicBuffer::getFlattenedSize(); if (size < sizeNeeded) return NO_MEMORY; @@ -453,12 +418,6 @@ status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& } else if (buf[0] == 'GBFR') { // old version, when usage bits were 32-bits flattenWordCount = 12; - } else if (buf[0] == 'BHBB') { // BufferHub backed buffer. -#ifndef LIBUI_IN_VNDK - return unflattenBufferHubBuffer(buffer, size); -#else - return BAD_TYPE; -#endif } else { return BAD_TYPE; } @@ -565,76 +524,6 @@ void GraphicBuffer::addDeathCallback(GraphicBufferDeathCallback deathCallback, v mDeathCallbacks.emplace_back(deathCallback, context); } -#ifndef LIBUI_IN_VNDK -status_t GraphicBuffer::flattenBufferHubBuffer(void*& buffer, size_t& size) const { - sp tokenHandle = mBufferHubBuffer->duplicate(); - if (tokenHandle == nullptr || tokenHandle->handle() == nullptr || - tokenHandle->handle()->numFds != 0) { - return BAD_VALUE; - } - - // Size needed for one label, one number of ints inside the token, one generation number and - // the token itself. - int numIntsInToken = tokenHandle->handle()->numInts; - const size_t sizeNeeded = static_cast(3 + numIntsInToken) * sizeof(int); - if (size < sizeNeeded) { - ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__, - static_cast(sizeNeeded), static_cast(size)); - return NO_MEMORY; - } - size -= sizeNeeded; - - int* buf = static_cast(buffer); - buf[0] = 'BHBB'; - buf[1] = numIntsInToken; - memcpy(buf + 2, tokenHandle->handle()->data, static_cast(numIntsInToken) * sizeof(int)); - buf[2 + numIntsInToken] = static_cast(mGenerationNumber); - - return NO_ERROR; -} - -status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size) { - const int* buf = static_cast(buffer); - int numIntsInToken = buf[1]; - // Size needed for one label, one number of ints inside the token, one generation number and - // the token itself. - const size_t sizeNeeded = static_cast(3 + numIntsInToken) * sizeof(int); - if (size < sizeNeeded) { - ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__, - static_cast(sizeNeeded), static_cast(size)); - return NO_MEMORY; - } - size -= sizeNeeded; - native_handle_t* importToken = native_handle_create(/*numFds=*/0, /*numInts=*/numIntsInToken); - memcpy(importToken->data, buf + 2, static_cast(buf[1]) * sizeof(int)); - sp importTokenHandle = NativeHandle::create(importToken, /*ownHandle=*/true); - std::unique_ptr bufferHubBuffer = BufferHubBuffer::import(importTokenHandle); - if (bufferHubBuffer == nullptr || bufferHubBuffer.get() == nullptr) { - return BAD_VALUE; - } - // Reconstruct this GraphicBuffer object using the new BufferHubBuffer object. - if (handle) { - free_handle(); - } - mId = 0; - mGenerationNumber = static_cast(buf[2 + numIntsInToken]); - mInitCheck = - initWithHandle(bufferHubBuffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE, - bufferHubBuffer->desc().width, bufferHubBuffer->desc().height, - static_cast(bufferHubBuffer->desc().format), - bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage, - bufferHubBuffer->desc().stride); - mBufferId = bufferHubBuffer->id(); - mBufferHubBuffer = std::move(bufferHubBuffer); - - return NO_ERROR; -} - -bool GraphicBuffer::isBufferHubBuffer() const { - return mBufferHubBuffer != nullptr; -} -#endif // LIBUI_IN_VNDK - // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h deleted file mode 100644 index 5ba189c2c3..0000000000 --- a/libs/ui/include/ui/BufferHubBuffer.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BUFFER_HUB_BUFFER_H_ -#define ANDROID_BUFFER_HUB_BUFFER_H_ - -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -class BufferHubBuffer { -public: - // Allocates a standalone BufferHubBuffer. - static std::unique_ptr create(uint32_t width, uint32_t height, - uint32_t layerCount, uint32_t format, - uint64_t usage, size_t userMetadataSize); - - // Imports the given token to a BufferHubBuffer. Not taking ownership of the token. - static std::unique_ptr import(const sp& token); - - BufferHubBuffer(const BufferHubBuffer&) = delete; - void operator=(const BufferHubBuffer&) = delete; - - virtual ~BufferHubBuffer(); - - // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in - // BufferHub share the same buffer id. - int id() const { return mId; } - - // Returns the buffer description, which is guaranteed to be faithful values from BufferHub. - const AHardwareBuffer_Desc& desc() const { return mBufferDesc; } - - // Duplicate the underlying Gralloc buffer handle. Caller is responsible to free the handle - // after use. - native_handle_t* duplicateHandle() { - return native_handle_clone(mBufferHandle.getNativeHandle()); - } - - const BufferHubEventFd& eventFd() const { return mEventFd; } - - // Returns the current value of MetadataHeader::bufferState. - uint32_t bufferState() const { return mBufferState->load(std::memory_order_acquire); } - - // A state mask which is unique to a buffer hub client among all its siblings sharing the same - // concrete graphic buffer. - uint32_t clientStateMask() const { return mClientStateMask; } - - size_t userMetadataSize() const { return mMetadata.userMetadataSize(); } - - // Returns true if the BufferClient is still alive. - bool isConnected() const { return mBufferClient->ping().isOk(); } - - // Returns true if the buffer is valid: non-null buffer handle, valid id, valid client bit mask, - // valid metadata and valid buffer client - bool isValid() const; - - // Gains the buffer for exclusive write permission. Read permission is implied once a buffer is - // gained. - // The buffer can be gained as long as there is no other client in acquired or gained state. - int gain(); - - // Posts the gained buffer for other buffer clients to use the buffer. - // The buffer can be posted iff the buffer state for this client is gained. - // After posting the buffer, this client is put to released state and does not have access to - // the buffer for this cycle of the usage of the buffer. - int post(); - - // Acquires the buffer for shared read permission. - // The buffer can be acquired iff the buffer state for this client is posted. - int acquire(); - - // Releases the buffer. - // The buffer can be released from any buffer state. - // After releasing the buffer, this client no longer have any permissions to the buffer for the - // current cycle of the usage of the buffer. - int release(); - - // Returns whether the buffer is released by all active clients or not. - bool isReleased() const; - - // Creates a token that stands for this BufferHubBuffer client and could be used for Import to - // create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying - // gralloc buffer and ashmem region for metadata. Not taking ownership of the token. - // Returns a valid token on success, nullptr on failure. - sp duplicate(); - -private: - BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format, - uint64_t usage, size_t userMetadataSize); - - BufferHubBuffer(const sp& token); - - int initWithBufferTraits(const frameworks::bufferhub::V1_0::BufferTraits& bufferTraits); - - // Global id for the buffer that is consistent across processes. - int mId = 0; - - // Client state mask of this BufferHubBuffer object. It is unique amoung all - // clients/users of the buffer. - uint32_t mClientStateMask = 0U; - - // Stores ground truth of the buffer. - AHardwareBuffer_Desc mBufferDesc; - - // Wraps the gralloc buffer handle of this buffer. - hardware::hidl_handle mBufferHandle; - - // Event fd used for signalling buffer state changes. Shared by all clients of the same buffer. - BufferHubEventFd mEventFd; - - // An ashmem-based metadata object. The same shared memory are mapped to the - // bufferhubd daemon and all buffer clients. - BufferHubMetadata mMetadata; - // Shortcuts to the atomics inside the header of mMetadata. - std::atomic* mBufferState = nullptr; - std::atomic* mFenceState = nullptr; - std::atomic* mActiveClientsBitMask = nullptr; - - // HwBinder backend - sp mBufferClient; -}; - -} // namespace android - -#endif // ANDROID_BUFFER_HUB_BUFFER_H_ diff --git a/libs/ui/include/ui/BufferHubEventFd.h b/libs/ui/include/ui/BufferHubEventFd.h deleted file mode 100644 index 8772304c0f..0000000000 --- a/libs/ui/include/ui/BufferHubEventFd.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BUFFER_HUB_EVENT_FD_H_ -#define ANDROID_BUFFER_HUB_EVENT_FD_H_ - -#include -#include - -namespace android { - -class BufferHubEventFd { -public: - /** - * Constructs a valid event fd. - */ - BufferHubEventFd(); - - /** - * Constructs from a valid event fd. Caller is responsible for the validity of the fd. Takes - * ownership. - */ - BufferHubEventFd(int fd); - - /** - * Returns whether this BufferHubEventFd holds a valid event_fd. - */ - bool isValid() const { return get() >= 0; } - - /** - * Returns the fd number of the BufferHubEventFd object. Note that there is no ownership - * transfer. - */ - int get() const { return mFd.get(); } - - /** - * Signals the eventfd. - */ - status_t signal() const; - - /** - * Clears the signal from this eventfd if it is signaled. - */ - status_t clear() const; - -private: - base::unique_fd mFd; -}; - -} // namespace android - -#endif // ANDROID_BUFFER_HUB_EVENT_FD_H_ diff --git a/libs/ui/include/ui/BufferHubMetadata.h b/libs/ui/include/ui/BufferHubMetadata.h deleted file mode 100644 index 3482507399..0000000000 --- a/libs/ui/include/ui/BufferHubMetadata.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_BUFFER_HUB_METADATA_H_ -#define ANDROID_BUFFER_HUB_METADATA_H_ - -#include -#include - -namespace android { - -namespace { -using base::unique_fd; -} // namespace - -class BufferHubMetadata { -public: - // Creates a new BufferHubMetadata backed by an ashmem region. - // - // @param userMetadataSize Size in bytes of the user defined metadata. The entire metadata - // shared memory region to be allocated is the size of canonical - // BufferHubDefs::MetadataHeader plus userMetadataSize. - static BufferHubMetadata create(size_t userMetadataSize); - - // Imports an existing BufferHubMetadata from an ashmem FD. - // - // @param ashmemFd Ashmem file descriptor representing an ashmem region. - static BufferHubMetadata import(unique_fd ashmemFd); - - BufferHubMetadata() = default; - - BufferHubMetadata(BufferHubMetadata&& other) { *this = std::move(other); } - - ~BufferHubMetadata(); - - BufferHubMetadata& operator=(BufferHubMetadata&& other) { - if (this != &other) { - mUserMetadataSize = other.mUserMetadataSize; - other.mUserMetadataSize = 0; - - mAshmemFd = std::move(other.mAshmemFd); - - // The old raw mMetadataHeader pointer must be cleared, otherwise the destructor will - // automatically mummap() the shared memory. - mMetadataHeader = other.mMetadataHeader; - other.mMetadataHeader = nullptr; - } - return *this; - } - - // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem fd and the ashmem - // has been mapped into virtual address space. - bool isValid() const { return mAshmemFd.get() != -1 && mMetadataHeader != nullptr; } - - size_t userMetadataSize() const { return mUserMetadataSize; } - size_t metadataSize() const { return mUserMetadataSize + BufferHubDefs::kMetadataHeaderSize; } - - const unique_fd& ashmemFd() const { return mAshmemFd; } - BufferHubDefs::MetadataHeader* metadataHeader() { return mMetadataHeader; } - -private: - BufferHubMetadata(size_t userMetadataSize, unique_fd ashmemFd, - BufferHubDefs::MetadataHeader* metadataHeader); - - BufferHubMetadata(const BufferHubMetadata&) = delete; - void operator=(const BufferHubMetadata&) = delete; - - size_t mUserMetadataSize = 0; - unique_fd mAshmemFd; - BufferHubDefs::MetadataHeader* mMetadataHeader = nullptr; -}; - -} // namespace android - -#endif // ANDROID_BUFFER_HUB_METADATA_H_ diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index c195342705..013505a2c9 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -38,10 +38,6 @@ namespace android { -#ifndef LIBUI_IN_VNDK -class BufferHubBuffer; -#endif // LIBUI_IN_VNDK - class GraphicBufferMapper; using GraphicBufferDeathCallback = std::function; @@ -147,11 +143,6 @@ public: GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inUsage, std::string requestorName = ""); -#ifndef LIBUI_IN_VNDK - // Create a GraphicBuffer from an existing BufferHubBuffer. - GraphicBuffer(std::unique_ptr buffer); -#endif // LIBUI_IN_VNDK - // return status status_t initCheck() const; @@ -163,7 +154,6 @@ public: uint32_t getLayerCount() const { return static_cast(layerCount); } Rect getBounds() const { return Rect(width, height); } uint64_t getId() const { return mId; } - int32_t getBufferId() const { return mBufferId; } uint32_t getGenerationNumber() const { return mGenerationNumber; } void setGenerationNumber(uint32_t generation) { @@ -225,11 +215,6 @@ public: void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context); -#ifndef LIBUI_IN_VNDK - // Returns whether this GraphicBuffer is backed by BufferHubBuffer. - bool isBufferHubBuffer() const; -#endif // LIBUI_IN_VNDK - private: ~GraphicBuffer(); @@ -275,12 +260,6 @@ private: uint64_t mId; - // System unique buffer ID. Note that this is different from mId, which is process unique. For - // GraphicBuffer backed by BufferHub, the mBufferId is a system unique identifier that stays the - // same cross process for the same chunck of underlying memory. Also note that this only applies - // to GraphicBuffers that are backed by BufferHub. - int32_t mBufferId = -1; - // Stores the generation number of this buffer. If this number does not // match the BufferQueue's internal generation number (set through // IGBP::setGenerationNumber), attempts to attach the buffer will fail. @@ -299,22 +278,6 @@ private: // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer. std::vector> mDeathCallbacks; - -#ifndef LIBUI_IN_VNDK - // Flatten this GraphicBuffer object if backed by BufferHubBuffer. - status_t flattenBufferHubBuffer(void*& buffer, size_t& size) const; - - // Unflatten into BufferHubBuffer backed GraphicBuffer. - // Unflatten will fail if the original GraphicBuffer object is destructed. For instance, a - // GraphicBuffer backed by BufferHubBuffer_1 flatten in process/thread A, transport the token - // to process/thread B through a socket, BufferHubBuffer_1 dies and bufferhub invalidated the - // token. Race condition occurs between the invalidation of the token in bufferhub process and - // process/thread B trying to unflatten and import the buffer with that token. - status_t unflattenBufferHubBuffer(void const*& buffer, size_t& size); - - // Stores a BufferHubBuffer that handles buffer signaling, identification. - std::unique_ptr mBufferHubBuffer; -#endif // LIBUI_IN_VNDK }; }; // namespace android diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 605c5a9ba0..b53342cb79 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -31,7 +31,6 @@ cc_test { cc_test { name: "GraphicBufferAllocator_test", header_libs: [ - "libdvr_headers", "libnativewindow_headers", ], static_libs: [ @@ -52,11 +51,9 @@ cc_test { cc_test { name: "GraphicBuffer_test", header_libs: [ - "libdvr_headers", "libnativewindow_headers", ], shared_libs: [ - "android.frameworks.bufferhub@1.0", "libcutils", "libhidlbase", "libui", @@ -71,11 +68,7 @@ cc_test { name: "GraphicBufferOverBinder_test", srcs: ["GraphicBufferOverBinder_test.cpp"], cflags: ["-Wall", "-Werror"], - header_libs: [ - "libdvr_headers", - ], shared_libs: [ - "android.frameworks.bufferhub@1.0", "libbinder", "libgui", "liblog", @@ -84,31 +77,6 @@ cc_test { ], } -cc_test { - name: "BufferHub_test", - header_libs: [ - "libdvr_headers", - "libnativewindow_headers", - ], - static_libs: [ - "libgmock", - ], - shared_libs: [ - "android.frameworks.bufferhub@1.0", - "libcutils", - "libhidlbase", - "liblog", - "libui", - "libutils" - ], - srcs: [ - "BufferHubBuffer_test.cpp", - "BufferHubEventFd_test.cpp", - "BufferHubMetadata_test.cpp", - ], - cflags: ["-Wall", "-Werror"], -} - cc_test { name: "Size_test", test_suites: ["device-tests"], diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp deleted file mode 100644 index 0c73a72deb..0000000000 --- a/libs/ui/tests/BufferHubBuffer_test.cpp +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "BufferHubBufferTest" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android { - -namespace { - -using ::android::BufferHubDefs::isAnyClientAcquired; -using ::android::BufferHubDefs::isAnyClientGained; -using ::android::BufferHubDefs::isAnyClientPosted; -using ::android::BufferHubDefs::isClientAcquired; -using ::android::BufferHubDefs::isClientGained; -using ::android::BufferHubDefs::isClientPosted; -using ::android::BufferHubDefs::isClientReleased; -using ::android::BufferHubDefs::kMetadataHeaderSize; -using ::android::frameworks::bufferhub::V1_0::IBufferHub; -using ::testing::IsNull; -using ::testing::NotNull; - -const int kWidth = 640; -const int kHeight = 480; -const int kLayerCount = 1; -const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888; -const int kUsage = 0; -const AHardwareBuffer_Desc kDesc = {kWidth, kHeight, kLayerCount, kFormat, - kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL}; -const size_t kUserMetadataSize = 1; - -class BufferHubBufferTest : public ::testing::Test { -protected: - void SetUp() override { - android::hardware::ProcessState::self()->startThreadPool(); - - if (!BufferHubServiceRunning()) { - // TODO(b/112940221): Enforce the test cross all devices once BufferHub lands in Android - // R for all Android varieties. - GTEST_SKIP() << "Skip test as the BufferHub service is not running."; - } - } - - bool BufferHubServiceRunning() { - sp bufferhub = IBufferHub::getService(); - return bufferhub.get() != nullptr; - } -}; - -bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) { - // Not comparing stride because it's unknown before allocation - return desc.format == other.format && desc.height == other.height && - desc.layers == other.layers && desc.usage == other.usage && desc.width == other.width; -} - -class BufferHubBufferStateTransitionTest : public BufferHubBufferTest { -protected: - void SetUp() override { - BufferHubBufferTest::SetUp(); - - if (IsSkipped()) { - // If the base class' SetUp() stated the test should be skipped, we should short - // circuit this sub-class' logic. - return; - } - - CreateTwoClientsOfABuffer(); - } - - std::unique_ptr b1; - uint32_t b1ClientMask = 0U; - std::unique_ptr b2; - uint32_t b2ClientMask = 0U; - -private: - // Creates b1 and b2 as the clients of the same buffer for testing. - void CreateTwoClientsOfABuffer(); -}; - -void BufferHubBufferStateTransitionTest::CreateTwoClientsOfABuffer() { - b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize); - ASSERT_THAT(b1, NotNull()); - b1ClientMask = b1->clientStateMask(); - ASSERT_NE(b1ClientMask, 0U); - - sp token = b1->duplicate(); - ASSERT_THAT(token, NotNull()); - - b2 = BufferHubBuffer::import(token); - ASSERT_THAT(b2, NotNull()); - - b2ClientMask = b2->clientStateMask(); - ASSERT_NE(b2ClientMask, 0U); - ASSERT_NE(b2ClientMask, b1ClientMask); -} - -TEST_F(BufferHubBufferTest, CreateBufferFails) { - // Buffer Creation will fail: BLOB format requires height to be 1. - auto b1 = BufferHubBuffer::create(kWidth, /*height=*/2, kLayerCount, - /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage, kUserMetadataSize); - - EXPECT_THAT(b1, IsNull()); - - // Buffer Creation will fail: user metadata size too large. - auto b2 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, - /*userMetadataSize=*/std::numeric_limits::max()); - - EXPECT_THAT(b2, IsNull()); - - // Buffer Creation will fail: user metadata size too large. - const size_t userMetadataSize = std::numeric_limits::max() - kMetadataHeaderSize; - auto b3 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, - userMetadataSize); - - EXPECT_THAT(b3, IsNull()); -} - -TEST_F(BufferHubBufferTest, CreateBuffer) { - auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, - kUserMetadataSize); - ASSERT_THAT(b1, NotNull()); - EXPECT_TRUE(b1->isConnected()); - EXPECT_TRUE(b1->isValid()); - EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), kDesc)); - EXPECT_EQ(b1->userMetadataSize(), kUserMetadataSize); -} - -TEST_F(BufferHubBufferTest, DuplicateAndImportBuffer) { - auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, - kUserMetadataSize); - ASSERT_THAT(b1, NotNull()); - EXPECT_TRUE(b1->isValid()); - - sp token = b1->duplicate(); - ASSERT_THAT(token, NotNull()); - - // The detached buffer should still be valid. - EXPECT_TRUE(b1->isConnected()); - EXPECT_TRUE(b1->isValid()); - - std::unique_ptr b2 = BufferHubBuffer::import(token); - - ASSERT_THAT(b2, NotNull()); - EXPECT_TRUE(b2->isValid()); - - EXPECT_TRUE(cmpAHardwareBufferDesc(b1->desc(), b2->desc())); - EXPECT_EQ(b1->userMetadataSize(), b2->userMetadataSize()); - - // These two buffer instances are based on the same physical buffer under the - // hood, so they should share the same id. - EXPECT_EQ(b1->id(), b2->id()); - // We use clientStateMask() to tell those two instances apart. - EXPECT_NE(b1->clientStateMask(), b2->clientStateMask()); - - // Both buffer instances should be in released state currently. - EXPECT_TRUE(b1->isReleased()); - EXPECT_TRUE(b2->isReleased()); - - // The event fd should behave like duped event fds. - const BufferHubEventFd& eventFd1 = b1->eventFd(); - ASSERT_GE(eventFd1.get(), 0); - const BufferHubEventFd& eventFd2 = b2->eventFd(); - ASSERT_GE(eventFd2.get(), 0); - - base::unique_fd epollFd(epoll_create(64)); - ASSERT_GE(epollFd.get(), 0); - - // Add eventFd1 to epoll set, and signal eventFd2. - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e), 0) << strerror(errno); - - std::array events; - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - eventFd2.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - - // The epoll fd is edge triggered, so it only responds to the eventFd once. - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - eventFd2.signal(); - eventFd2.clear(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); -} - -TEST_F(BufferHubBufferTest, ImportFreedBuffer) { - auto b1 = BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, - kUserMetadataSize); - ASSERT_THAT(b1, NotNull()); - EXPECT_TRUE(b1->isValid()); - - sp token = b1->duplicate(); - ASSERT_THAT(token, NotNull()); - - // Explicitly destroy b1. Backend buffer should be freed and token becomes invalid - b1.reset(); - - std::unique_ptr b2 = BufferHubBuffer::import(token); - - // Import should fail with INVALID_TOKEN - EXPECT_THAT(b2, IsNull()); -} - -// nullptr must not crash the service -TEST_F(BufferHubBufferTest, ImportNullToken) { - auto b1 = BufferHubBuffer::import(nullptr); - EXPECT_THAT(b1, IsNull()); -} - -TEST_F(BufferHubBufferTest, ImportInvalidToken) { - native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1); - token->data[0] = 0; - - sp tokenHandle = NativeHandle::create(token, /*ownHandle=*/true); - auto b1 = BufferHubBuffer::import(tokenHandle); - - EXPECT_THAT(b1, IsNull()); -} - -TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) { - ASSERT_TRUE(b1->isReleased()); - - // Successful gaining the buffer should change the buffer state bit of b1 to - // gained state, other client state bits to released state. - EXPECT_EQ(b1->gain(), 0); - EXPECT_TRUE(isClientGained(b1->bufferState(), b1ClientMask)); -} - -TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromGainedState) { - ASSERT_EQ(b1->gain(), 0); - auto currentBufferState = b1->bufferState(); - ASSERT_TRUE(isClientGained(currentBufferState, b1ClientMask)); - - // Gaining from gained state by the same client should not return error. - EXPECT_EQ(b1->gain(), 0); - - // Gaining from gained state by another client should return error. - EXPECT_EQ(b2->gain(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromAcquiredState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_EQ(b2->acquire(), 0); - ASSERT_TRUE(isAnyClientAcquired(b1->bufferState())); - - // Gaining from acquired state should fail. - EXPECT_EQ(b1->gain(), -EBUSY); - EXPECT_EQ(b2->gain(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromOtherClientInPostedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_TRUE(isAnyClientPosted(b1->bufferState())); - - // Gaining a buffer who has other posted client should succeed. - EXPECT_EQ(b1->gain(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromSelfInPostedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_TRUE(isAnyClientPosted(b1->bufferState())); - - // A posted client should be able to gain the buffer when there is no other clients in - // acquired state. - EXPECT_EQ(b2->gain(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromOtherInGainedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_TRUE(isClientGained(b1->bufferState(), b1ClientMask)); - - EXPECT_EQ(b2->post(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromSelfInGainedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_TRUE(isClientGained(b1->bufferState(), b1ClientMask)); - - EXPECT_EQ(b1->post(), 0); - auto currentBufferState = b1->bufferState(); - EXPECT_TRUE(isClientReleased(currentBufferState, b1ClientMask)); - EXPECT_TRUE(isClientPosted(currentBufferState, b2ClientMask)); -} - -TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromPostedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_TRUE(isAnyClientPosted(b1->bufferState())); - - // Post from posted state should fail. - EXPECT_EQ(b1->post(), -EBUSY); - EXPECT_EQ(b2->post(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromAcquiredState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_EQ(b2->acquire(), 0); - ASSERT_TRUE(isAnyClientAcquired(b1->bufferState())); - - // Posting from acquired state should fail. - EXPECT_EQ(b1->post(), -EBUSY); - EXPECT_EQ(b2->post(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromReleasedState) { - ASSERT_TRUE(b1->isReleased()); - - // Posting from released state should fail. - EXPECT_EQ(b1->post(), -EBUSY); - EXPECT_EQ(b2->post(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInPostedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_TRUE(isClientPosted(b1->bufferState(), b2ClientMask)); - - // Acquire from posted state should pass. - EXPECT_EQ(b2->acquire(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromOtherInPostedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_TRUE(isClientPosted(b1->bufferState(), b2ClientMask)); - - // Acquire from released state should fail, although there are other clients - // in posted state. - EXPECT_EQ(b1->acquire(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromSelfInAcquiredState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_EQ(b2->acquire(), 0); - auto currentBufferState = b1->bufferState(); - ASSERT_TRUE(isClientAcquired(currentBufferState, b2ClientMask)); - - // Acquiring from acquired state by the same client should not error out. - EXPECT_EQ(b2->acquire(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromReleasedState) { - ASSERT_TRUE(b1->isReleased()); - - // Acquiring form released state should fail. - EXPECT_EQ(b1->acquire(), -EBUSY); - EXPECT_EQ(b2->acquire(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromGainedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_TRUE(isAnyClientGained(b1->bufferState())); - - // Acquiring from gained state should fail. - EXPECT_EQ(b1->acquire(), -EBUSY); - EXPECT_EQ(b2->acquire(), -EBUSY); -} - -TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInReleasedState) { - ASSERT_TRUE(b1->isReleased()); - - EXPECT_EQ(b1->release(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInGainedState) { - ASSERT_TRUE(b1->isReleased()); - ASSERT_EQ(b1->gain(), 0); - ASSERT_TRUE(isAnyClientGained(b1->bufferState())); - - EXPECT_EQ(b1->release(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInPostedState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_TRUE(isAnyClientPosted(b1->bufferState())); - - EXPECT_EQ(b2->release(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInAcquiredState) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_EQ(b2->acquire(), 0); - ASSERT_TRUE(isAnyClientAcquired(b1->bufferState())); - - EXPECT_EQ(b2->release(), 0); -} - -TEST_F(BufferHubBufferStateTransitionTest, BasicUsage) { - // 1 producer buffer and 1 consumer buffer initialised in testcase setup. - // Test if this set of basic operation succeed: - // Producer post three times to the consumer, and released by consumer. - for (int i = 0; i < 3; ++i) { - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - ASSERT_EQ(b2->acquire(), 0); - ASSERT_EQ(b2->release(), 0); - } -} - -TEST_F(BufferHubBufferTest, createNewConsumerAfterGain) { - // Create a poducer buffer and gain. - std::unique_ptr b1 = - BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, - kUserMetadataSize); - ASSERT_THAT(b1, NotNull()); - ASSERT_EQ(b1->gain(), 0); - - // Create a consumer of the buffer and test if the consumer can acquire the - // buffer if producer posts. - sp token = b1->duplicate(); - ASSERT_THAT(token, NotNull()); - - std::unique_ptr b2 = BufferHubBuffer::import(token); - - ASSERT_THAT(b2, NotNull()); - ASSERT_NE(b1->clientStateMask(), b2->clientStateMask()); - - ASSERT_EQ(b1->post(), 0); - EXPECT_EQ(b2->acquire(), 0); -} - -TEST_F(BufferHubBufferTest, createNewConsumerAfterPost) { - // Create a poducer buffer and post. - std::unique_ptr b1 = - BufferHubBuffer::create(kWidth, kHeight, kLayerCount, kFormat, kUsage, - kUserMetadataSize); - ASSERT_EQ(b1->gain(), 0); - ASSERT_EQ(b1->post(), 0); - - // Create a consumer of the buffer and test if the consumer can acquire the - // buffer if producer posts. - sp token = b1->duplicate(); - ASSERT_THAT(token, NotNull()); - - std::unique_ptr b2 = BufferHubBuffer::import(token); - - ASSERT_THAT(b2, NotNull()); - ASSERT_NE(b1->clientStateMask(), b2->clientStateMask()); - - EXPECT_EQ(b2->acquire(), 0); -} - -} // namespace - -} // namespace android diff --git a/libs/ui/tests/BufferHubEventFd_test.cpp b/libs/ui/tests/BufferHubEventFd_test.cpp deleted file mode 100644 index ef1781f9d2..0000000000 --- a/libs/ui/tests/BufferHubEventFd_test.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "BufferHubEventFdTest" - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace android { - -namespace { - -const int kTimeout = 100; -const std::chrono::milliseconds kTimeoutMs(kTimeout); -const int kTestRuns = 5; - -using ::testing::Contains; -using BufferHubEventFdTest = ::testing::Test; - -} // namespace - -TEST_F(BufferHubEventFdTest, EventFd_testSingleEpollFd) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - - base::unique_fd epollFd(epoll_create(64)); - ASSERT_GE(epollFd.get(), 0); - - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - std::array events; - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - eventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - - // The epoll fd is edge triggered, so it only responds to the eventFd once. - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - // Check that it can receive consecutive signal. - eventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - // Check that it can receive consecutive signal from a duplicated eventfd. - BufferHubEventFd dupEventFd(dup(eventFd.get())); - ASSERT_TRUE(dupEventFd.isValid()); - dupEventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - dupEventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); -} - -TEST_F(BufferHubEventFdTest, EventFd_testCreateEpollFdAndAddSignaledEventFd) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - eventFd.signal(); - - base::unique_fd epollFd(epoll_create(64)); - ASSERT_GE(epollFd.get(), 0); - - // Make sure that the epoll set has not been signal yet. - std::array events; - ASSERT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - // Check that adding an signaled fd into this epoll set will trigger the epoll set. - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - - // The epoll fd is edge triggered, so it only responds to the eventFd once. - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); -} - -TEST_F(BufferHubEventFdTest, EventFd_testAddSignaledEventFdToEpollFd) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - - base::unique_fd epollFd(epoll_create(64)); - ASSERT_GE(epollFd.get(), 0); - - eventFd.signal(); - - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - std::array events; - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - - // The epoll fd is edge triggered, so it only responds to the eventFd once. - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); -} - -TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromAEventFd) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - base::unique_fd epollFd(epoll_create(64)); - ASSERT_GE(epollFd.get(), 0); - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - std::array events; - for (int i = 0; i < kTestRuns; ++i) { - eventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - } -} - -TEST_F(BufferHubEventFdTest, EventFd_testConsecutiveSignalsFromADuplicatedEventFd) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - base::unique_fd epollFd(epoll_create(64)); - ASSERT_GE(epollFd.get(), 0); - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - BufferHubEventFd dupEventFd(dup(eventFd.get())); - ASSERT_TRUE(dupEventFd.isValid()); - - std::array events; - for (int i = 0; i < kTestRuns; ++i) { - dupEventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - } -} - -TEST_F(BufferHubEventFdTest, EventFd_testClear) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - - base::unique_fd epollFd(epoll_create(64)); - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - - ASSERT_GE(epollFd.get(), 0); - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - eventFd.signal(); - eventFd.clear(); - - std::array events; - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); -} - -TEST_F(BufferHubEventFdTest, EventFd_testDupEventFd) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - - base::unique_fd epollFd(epoll_create(64)); - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - - ASSERT_GE(epollFd.get(), 0); - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - // Technically, the dupliated eventFd and the original eventFd are pointing - // to the same kernel object. This test signals the duplicated eventFd but epolls the origianl - // eventFd. - BufferHubEventFd dupedEventFd(dup(eventFd.get())); - ASSERT_GE(dupedEventFd.get(), 0); - - std::array events; - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - dupedEventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - - // The epoll fd is edge triggered, so it only responds to the eventFd once. - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - dupedEventFd.signal(); - - dupedEventFd.clear(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); -} - -TEST_F(BufferHubEventFdTest, EventFd_testTwoEpollFds) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - - base::unique_fd epollFd1(epoll_create(64)); - base::unique_fd epollFd2(epoll_create(64)); - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - - ASSERT_GE(epollFd1.get(), 0); - ASSERT_GE(epollFd2.get(), 0); - - // Register the same eventFd to two EpollFds. - ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - std::array events; - EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0); - EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0); - - eventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 1); - - // The epoll fd is edge triggered, so it only responds to the eventFd once. - EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0); - EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0); - - eventFd.signal(); - EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 1); - - eventFd.clear(); - EXPECT_EQ(epoll_wait(epollFd1.get(), events.data(), events.size(), 0), 0); - EXPECT_EQ(epoll_wait(epollFd2.get(), events.data(), events.size(), 0), 0); -} - -TEST_F(BufferHubEventFdTest, EventFd_testTwoEventFds) { - BufferHubEventFd eventFd1; - BufferHubEventFd eventFd2; - - ASSERT_TRUE(eventFd1.isValid()); - ASSERT_TRUE(eventFd2.isValid()); - - base::unique_fd epollFd(epoll_create(64)); - epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}}; - epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}}; - - ASSERT_GE(epollFd.get(), 0); - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0); - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0); - - std::array events; - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - // Signal one by one. - eventFd1.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(events[0].data.u32, e1.data.u32); - - eventFd2.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); - EXPECT_EQ(events[0].data.u32, e2.data.u32); - - // Signal both. - eventFd1.signal(); - eventFd2.signal(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 2); - - uint32_t u32s[] = {events[0].data.u32, events[1].data.u32}; - EXPECT_THAT(u32s, Contains(e1.data.u32)); - EXPECT_THAT(u32s, Contains(e2.data.u32)); - - // The epoll fd is edge triggered, so it only responds to the eventFd once. - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0); - - eventFd1.signal(); - eventFd2.signal(); - eventFd2.clear(); - EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 1); -} - -TEST_F(BufferHubEventFdTest, EventFd_testPollingThreadWithTwoEventFds) { - BufferHubEventFd eventFd1; - BufferHubEventFd eventFd2; - - ASSERT_TRUE(eventFd1.isValid()); - ASSERT_TRUE(eventFd2.isValid()); - - base::unique_fd epollFd(epoll_create(64)); - epoll_event e1 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 1}}; - epoll_event e2 = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 2}}; - - ASSERT_GE(epollFd.get(), 0); - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e1), 0); - ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd2.get(), &e2), 0); - - int countEvent1 = 0; - int countEvent2 = 0; - std::atomic stop{false}; - std::mutex mx; - std::condition_variable cv; - - std::thread pollingThread([&] { - std::array events; - while (true) { - if (stop.load()) { - break; - } - int ret = epoll_wait(epollFd.get(), events.data(), events.size(), kTimeout); - ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed."); - - std::lock_guard lock(mx); - for (int i = 0; i < ret; i++) { - if (events[i].data.u32 == e1.data.u32) { - countEvent1++; - cv.notify_one(); - } else if (events[i].data.u32 == e2.data.u32) { - countEvent2++; - cv.notify_one(); - } - } - } - }); - - { - std::unique_lock lock(mx); - - eventFd1.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 1; })); - - eventFd1.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 2; })); - - eventFd2.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 1; })); - - eventFd1.clear(); - eventFd2.clear(); - EXPECT_EQ(countEvent1, 2); - EXPECT_EQ(countEvent2, 1); - - eventFd1.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent1 == 3; })); - - eventFd2.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEvent2 == 2; })); - } - - stop.store(true); - pollingThread.join(); -} - -TEST_F(BufferHubEventFdTest, EventFd_testTwoPollingThreads) { - BufferHubEventFd eventFd; - ASSERT_TRUE(eventFd.isValid()); - - base::unique_fd epollFd1(epoll_create(64)); - base::unique_fd epollFd2(epoll_create(64)); - epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}}; - - ASSERT_GE(epollFd1.get(), 0); - ASSERT_GE(epollFd2.get(), 0); - - // Register the same eventFd to two EpollFds. - ASSERT_EQ(epoll_ctl(epollFd1.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - ASSERT_EQ(epoll_ctl(epollFd2.get(), EPOLL_CTL_ADD, eventFd.get(), &e), 0); - - int countEpoll1 = 0; - int countEpoll2 = 0; - std::atomic stop{false}; - std::mutex mx; - std::condition_variable cv; - - std::thread pollingThread1([&] { - std::array events; - while (!stop.load()) { - int ret = epoll_wait(epollFd1.get(), events.data(), events.size(), kTimeout); - ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed."); - - if (ret > 0) { - std::lock_guard lock(mx); - countEpoll1++; - cv.notify_one(); - } - } - }); - - std::thread pollingThread2([&] { - std::array events; - while (!stop.load()) { - int ret = epoll_wait(epollFd2.get(), events.data(), events.size(), kTimeout); - ALOGE_IF(ret < 0 && errno != ETIMEDOUT, "Epoll failed."); - - if (ret > 0) { - std::lock_guard lock(mx); - countEpoll2++; - cv.notify_one(); - } - } - }); - - { - std::unique_lock lock(mx); - - eventFd.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 1; })); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 1; })); - - eventFd.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 2; })); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 2; })); - - eventFd.clear(); - EXPECT_EQ(countEpoll1, 2); - EXPECT_EQ(countEpoll2, 2); - - eventFd.signal(); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll1 == 3; })); - EXPECT_TRUE(cv.wait_for(lock, kTimeoutMs, [&] { return countEpoll2 == 3; })); - } - - stop.store(true); - pollingThread1.join(); - pollingThread2.join(); -} - -} // namespace android diff --git a/libs/ui/tests/BufferHubMetadata_test.cpp b/libs/ui/tests/BufferHubMetadata_test.cpp deleted file mode 100644 index eb978cabc6..0000000000 --- a/libs/ui/tests/BufferHubMetadata_test.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -namespace android { -namespace dvr { - -constexpr size_t kEmptyUserMetadataSize = 0; - -class BufferHubMetadataTest : public ::testing::Test {}; - -TEST_F(BufferHubMetadataTest, Create_UserMetdataSizeTooBig) { - BufferHubMetadata m1 = BufferHubMetadata::create(std::numeric_limits::max()); - EXPECT_FALSE(m1.isValid()); -} - -TEST_F(BufferHubMetadataTest, Create_Success) { - BufferHubMetadata m1 = BufferHubMetadata::create(kEmptyUserMetadataSize); - EXPECT_TRUE(m1.isValid()); - EXPECT_NE(m1.metadataHeader(), nullptr); -} - -TEST_F(BufferHubMetadataTest, Import_Success) { - BufferHubMetadata m1 = BufferHubMetadata::create(kEmptyUserMetadataSize); - EXPECT_TRUE(m1.isValid()); - EXPECT_NE(m1.metadataHeader(), nullptr); - - unique_fd h2 = unique_fd(dup(m1.ashmemFd().get())); - EXPECT_NE(h2.get(), -1); - - BufferHubMetadata m2 = BufferHubMetadata::import(std::move(h2)); - EXPECT_EQ(h2.get(), -1); - EXPECT_TRUE(m1.isValid()); - BufferHubDefs::MetadataHeader* mh1 = m1.metadataHeader(); - EXPECT_NE(mh1, nullptr); - - // Check if the newly allocated buffer is initialized in released state (i.e. - // state equals to 0U). - EXPECT_TRUE(mh1->bufferState.load() == 0U); - - EXPECT_TRUE(m2.isValid()); - BufferHubDefs::MetadataHeader* mh2 = m2.metadataHeader(); - EXPECT_NE(mh2, nullptr); - - // Check if the newly allocated buffer is initialized in released state (i.e. - // state equals to 0U). - EXPECT_TRUE(mh2->bufferState.load() == 0U); -} - -TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) { - BufferHubMetadata m1 = BufferHubMetadata::create(sizeof(int)); - EXPECT_TRUE(m1.isValid()); - EXPECT_NE(m1.metadataHeader(), nullptr); - EXPECT_NE(m1.ashmemFd().get(), -1); - EXPECT_EQ(m1.userMetadataSize(), sizeof(int)); - - BufferHubMetadata m2 = std::move(m1); - - // After the move, the metadata header (a raw pointer) should be reset in the older buffer. - EXPECT_EQ(m1.metadataHeader(), nullptr); - EXPECT_NE(m2.metadataHeader(), nullptr); - - EXPECT_EQ(m1.ashmemFd().get(), -1); - EXPECT_NE(m2.ashmemFd().get(), -1); - - EXPECT_EQ(m1.userMetadataSize(), 0U); - EXPECT_EQ(m2.userMetadataSize(), sizeof(int)); - - BufferHubMetadata m3{std::move(m2)}; - - // After the move, the metadata header (a raw pointer) should be reset in the older buffer. - EXPECT_EQ(m2.metadataHeader(), nullptr); - EXPECT_NE(m3.metadataHeader(), nullptr); - - EXPECT_EQ(m2.ashmemFd().get(), -1); - EXPECT_NE(m3.ashmemFd().get(), -1); - - EXPECT_EQ(m2.userMetadataSize(), 0U); - EXPECT_EQ(m3.userMetadataSize(), sizeof(int)); -} - -} // namespace dvr -} // namespace android diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp index 7c0a44a64f..126a945a0a 100644 --- a/libs/ui/tests/GraphicBufferOverBinder_test.cpp +++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -37,7 +36,6 @@ constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; static const String16 kTestServiceName = String16("GraphicBufferOverBinderTestService"); enum GraphicBufferOverBinderTestServiceCode { GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, - GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER, }; class GraphicBufferOverBinderTestService : public BBinder { @@ -46,21 +44,6 @@ public: // GraphicBuffer mGraphicBuffer = new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage); - ALOGI("mGraphicBuffer id %" PRIi32, mGraphicBuffer->getBufferId()); - - // BufferHub-backed GraphicBuffer - std::unique_ptr bufferHubBuffer = - BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, - kTestUsage, /*userMetadataSize=*/0); - mBufferhubBackedGraphicBuffer = new GraphicBuffer(std::move(bufferHubBuffer)); - if (!mBufferhubBackedGraphicBuffer->isBufferHubBuffer()) { - ALOGE("Failed to back GraphicBuffer with BufferHub."); - } - if (bufferHubBuffer != nullptr) { - ALOGE("Failed to move BufferHubBuffer to GraphicBuffer"); - } - ALOGI("mBufferhubBackedGraphicBuffer id %" PRIi32, - mBufferhubBackedGraphicBuffer->getBufferId()); } ~GraphicBufferOverBinderTestService() = default; @@ -71,9 +54,6 @@ public: case GRAPHIC_BUFFER: { return reply->write(*mGraphicBuffer); } - case GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER: { - return reply->write(*mBufferhubBackedGraphicBuffer); - } default: return UNKNOWN_TRANSACTION; }; @@ -81,7 +61,6 @@ public: protected: sp mGraphicBuffer; - sp mBufferhubBackedGraphicBuffer; }; static int runBinderServer() { @@ -138,17 +117,6 @@ TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferOverBinder) { sp gb; EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER), OK); EXPECT_NE(gb, nullptr); - EXPECT_FALSE(gb->isBufferHubBuffer()); - void* vaddr; - EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); - EXPECT_EQ(gb->unlock(), OK); -} - -TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferFromBufferHubBufferOverBinder) { - sp gb; - EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER), NO_ERROR); - EXPECT_NE(gb, nullptr); - EXPECT_TRUE(gb->isBufferHubBuffer()); void* vaddr; EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); EXPECT_EQ(gb->unlock(), OK); diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp index 5e0b094b7b..19551b3604 100644 --- a/libs/ui/tests/GraphicBuffer_test.cpp +++ b/libs/ui/tests/GraphicBuffer_test.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "GraphicBufferTest" -#include #include #include @@ -27,7 +26,6 @@ namespace { constexpr uint32_t kTestWidth = 1024; constexpr uint32_t kTestHeight = 1; -constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB; constexpr uint32_t kTestLayerCount = 1; constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; @@ -68,88 +66,4 @@ TEST_F(GraphicBufferTest, AllocateBadDimensions) { ASSERT_EQ(BAD_VALUE, gb2->initCheck()); } -TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) { - std::unique_ptr b1 = - BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, - kTestUsage, /*userMetadataSize=*/0); - ASSERT_NE(b1, nullptr); - EXPECT_TRUE(b1->isValid()); - - sp gb(new GraphicBuffer(std::move(b1))); - EXPECT_TRUE(gb->isBufferHubBuffer()); - - EXPECT_EQ(gb->getWidth(), kTestWidth); - EXPECT_EQ(gb->getHeight(), kTestHeight); - EXPECT_EQ(static_cast(gb->getPixelFormat()), kTestFormat); - EXPECT_EQ(gb->getUsage(), kTestUsage); - EXPECT_EQ(gb->getLayerCount(), kTestLayerCount); -} - -TEST_F(GraphicBufferTest, InvalidBufferIdForNoneBufferHubBuffer) { - sp gb( - new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, kTestUsage)); - EXPECT_FALSE(gb->isBufferHubBuffer()); - EXPECT_EQ(gb->getBufferId(), -1); -} - -TEST_F(GraphicBufferTest, BufferIdMatchesBufferHubBufferId) { - std::unique_ptr b1 = - BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, - kTestUsage, /*userMetadataSize=*/0); - EXPECT_NE(b1, nullptr); - EXPECT_TRUE(b1->isValid()); - - int b1_id = b1->id(); - EXPECT_GE(b1_id, 0); - - sp gb(new GraphicBuffer(std::move(b1))); - EXPECT_TRUE(gb->isBufferHubBuffer()); - EXPECT_EQ(gb->getBufferId(), b1_id); -} - -TEST_F(GraphicBufferTest, flattenAndUnflatten) { - std::unique_ptr b1 = - BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, - kTestUsage, /*userMetadataSize=*/0); - ASSERT_NE(b1, nullptr); - sp gb1(new GraphicBuffer(std::move(b1))); - gb1->setGenerationNumber(42); - - size_t flattenedSize = gb1->getFlattenedSize(); - EXPECT_EQ(flattenedSize, 48); - size_t fdCount = gb1->getFdCount(); - EXPECT_EQ(fdCount, 0); - - int data[flattenedSize]; - int fds[0]; - - // Make copies of needed items since flatten modifies them. - size_t flattenedSizeCopy = flattenedSize; - size_t fdCountCopy = fdCount; - void* dataStart = data; - int* fdsStart = fds; - status_t err = gb1->flatten(dataStart, flattenedSizeCopy, fdsStart, fdCountCopy); - ASSERT_EQ(err, NO_ERROR); - EXPECT_EQ(flattenedSizeCopy, 0); - EXPECT_EQ(fdCountCopy, 0); - - size_t unflattenSize = flattenedSize; - size_t unflattenFdCount = fdCount; - const void* unflattenData = static_cast(dataStart); - const int* unflattenFdData = static_cast(fdsStart); - - GraphicBuffer* gb2 = new GraphicBuffer(); - err = gb2->unflatten(unflattenData, unflattenSize, unflattenFdData, unflattenFdCount); - ASSERT_EQ(err, NO_ERROR); - EXPECT_TRUE(gb2->isBufferHubBuffer()); - - EXPECT_EQ(gb2->getWidth(), kTestWidth); - EXPECT_EQ(gb2->getHeight(), kTestHeight); - EXPECT_EQ(static_cast(gb2->getPixelFormat()), kTestFormat); - EXPECT_EQ(gb2->getUsage(), kTestUsage); - EXPECT_EQ(gb2->getLayerCount(), kTestLayerCount); - EXPECT_EQ(gb1->getBufferId(), gb2->getBufferId()); - EXPECT_EQ(gb2->getGenerationNumber(), 42); -} - } // namespace android diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp deleted file mode 100644 index 2bb6aef3a5..0000000000 --- a/services/bufferhub/Android.bp +++ /dev/null @@ -1,77 +0,0 @@ -// -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -cc_library_shared { - name: "libbufferhubservice", - cflags: [ - "-DLOG_TAG=\"libbufferhubservice\"", - "-Wall", - "-Werror", - "-Wextra", - ], - srcs: [ - "BufferClient.cpp", - "BufferHubIdGenerator.cpp", - "BufferHubService.cpp", - "BufferNode.cpp", - ], - header_libs: [ - "libdvr_headers", - "libnativewindow_headers", - ], - shared_libs: [ - "android.frameworks.bufferhub@1.0", - "libcrypto", - "libcutils", - "libhidlbase", - "liblog", - "libui", - "libutils", - ], - export_include_dirs: [ - "include" - ], -} - -cc_binary { - name: "android.frameworks.bufferhub@1.0-service", - relative_install_path: "hw", - srcs: [ - "main_bufferhub.cpp" - ], - header_libs: [ - "libdvr_headers", - "libnativewindow_headers", - ], - shared_libs: [ - "android.frameworks.bufferhub@1.0", - "libbufferhubservice", - "libcrypto", - "libcutils", - "libhidlbase", - "liblog", - "libui", - "libutils", - ], - cflags: [ - "-DLOG_TAG=\"bufferhub\"", - "-Wall", - "-Werror", - "-Wextra", - ], - init_rc: ["android.frameworks.bufferhub@1.0-service.rc"], - vintf_fragments: ["android.frameworks.bufferhub@1.0-service.xml"], -} diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp deleted file mode 100644 index ec7e535699..0000000000 --- a/services/bufferhub/BufferClient.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -using hardware::hidl_handle; -using hardware::Void; - -BufferClient* BufferClient::create(BufferHubService* service, - const std::shared_ptr& node) { - if (!service) { - ALOGE("%s: service cannot be nullptr.", __FUNCTION__); - return nullptr; - } else if (!node) { - ALOGE("%s: node cannot be nullptr.", __FUNCTION__); - return nullptr; - } - return new BufferClient(service, node); -} - -BufferClient::~BufferClient() { - { - std::lock_guard lock(mClosedMutex); - if (!mClosed) { - ALOGW("%s: client of buffer #%d destroyed without close. Closing it now.", __FUNCTION__, - mBufferNode->id()); - } - } - - close(); -} - -Return BufferClient::close() { - std::lock_guard lock(mClosedMutex); - if (mClosed) { - return BufferHubStatus::CLIENT_CLOSED; - } - - getService()->onClientClosed(this); - mBufferNode.reset(); - mClosed = true; - return BufferHubStatus::NO_ERROR; -} - -Return BufferClient::duplicate(duplicate_cb _hidl_cb) { - std::lock_guard lock(mClosedMutex); - if (mClosed) { - _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::CLIENT_CLOSED); - return Void(); - } - - if (!mBufferNode) { - // Should never happen - ALOGE("%s: node is missing.", __FUNCTION__); - _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::BUFFER_FREED); - return Void(); - } - - const hidl_handle token = getService()->registerToken(this); - _hidl_cb(/*token=*/token, /*status=*/BufferHubStatus::NO_ERROR); - return Void(); -} - -sp BufferClient::getService() { - sp service = mService.promote(); - if (service == nullptr) { - // Should never happen. Kill the process. - LOG_FATAL("%s: service died.", __FUNCTION__); - } - - return service; -} - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android \ No newline at end of file diff --git a/services/bufferhub/BufferHubIdGenerator.cpp b/services/bufferhub/BufferHubIdGenerator.cpp deleted file mode 100644 index 2c12f0e26d..0000000000 --- a/services/bufferhub/BufferHubIdGenerator.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -BufferHubIdGenerator& BufferHubIdGenerator::getInstance() { - static BufferHubIdGenerator generator; - - return generator; -} - -int BufferHubIdGenerator::getId() { - std::lock_guard lock(mIdsInUseMutex); - - do { - if (++mLastId >= std::numeric_limits::max()) { - mLastId = 0; - } - } while (mIdsInUse.find(mLastId) != mIdsInUse.end()); - - mIdsInUse.insert(mLastId); - return mLastId; -} - -void BufferHubIdGenerator::freeId(int id) { - std::lock_guard lock(mIdsInUseMutex); - auto iter = mIdsInUse.find(id); - if (iter != mIdsInUse.end()) { - mIdsInUse.erase(iter); - } else { - ALOGW("%s: Cannot free nonexistent id #%d", __FUNCTION__, id); - } -} - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp deleted file mode 100644 index 7a3472fa7e..0000000000 --- a/services/bufferhub/BufferHubService.cpp +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using ::android::BufferHubDefs::MetadataHeader; -using ::android::hardware::Void; - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -BufferHubService::BufferHubService() { - std::mt19937_64 randomEngine; - randomEngine.seed(time(nullptr)); - - mKey = randomEngine(); -} - -Return BufferHubService::allocateBuffer(const HardwareBufferDescription& description, - const uint32_t userMetadataSize, - allocateBuffer_cb _hidl_cb) { - AHardwareBuffer_Desc desc; - memcpy(&desc, &description, sizeof(AHardwareBuffer_Desc)); - - std::shared_ptr node = - std::make_shared(desc.width, desc.height, desc.layers, desc.format, - desc.usage, userMetadataSize, - BufferHubIdGenerator::getInstance().getId()); - if (node == nullptr || !node->isValid()) { - ALOGE("%s: creating BufferNode failed.", __FUNCTION__); - _hidl_cb(/*status=*/BufferHubStatus::ALLOCATION_FAILED, /*bufferClient=*/nullptr, - /*bufferTraits=*/{}); - return Void(); - } - - sp client = BufferClient::create(this, node); - // Add it to list for bookkeeping and dumpsys. - std::lock_guard lock(mClientSetMutex); - mClientSet.emplace(client); - - // Allocate memory for bufferInfo of type hidl_handle on the stack. See - // http://aosp/286282 for the usage of NATIVE_HANDLE_DECLARE_STORAGE. - NATIVE_HANDLE_DECLARE_STORAGE(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds, - BufferHubDefs::kBufferInfoNumInts); - hidl_handle bufferInfo = - buildBufferInfo(bufferInfoStorage, node->id(), node->addNewActiveClientsBitToMask(), - node->userMetadataSize(), node->metadata().ashmemFd(), - node->eventFd().get()); - // During the gralloc allocation carried out by BufferNode, gralloc allocator will populate the - // fields of its HardwareBufferDescription (i.e. strides) according to the actual - // gralloc implementation. We need to read those fields back and send them to the client via - // BufferTraits. - HardwareBufferDescription allocatedBufferDesc; - memcpy(&allocatedBufferDesc, &node->bufferDesc(), sizeof(AHardwareBuffer_Desc)); - BufferTraits bufferTraits = {/*bufferDesc=*/allocatedBufferDesc, - /*bufferHandle=*/hidl_handle(node->bufferHandle()), - /*bufferInfo=*/std::move(bufferInfo)}; - - _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client, - /*bufferTraits=*/std::move(bufferTraits)); - return Void(); -} - -Return BufferHubService::importBuffer(const hidl_handle& tokenHandle, - importBuffer_cb _hidl_cb) { - if (!tokenHandle.getNativeHandle() || tokenHandle->numFds != 0 || tokenHandle->numInts <= 1) { - // nullptr handle or wrong format - _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr, - /*bufferTraits=*/{}); - return Void(); - } - - int tokenId = tokenHandle->data[0]; - - wp originClientWp; - { - std::lock_guard lock(mTokenMutex); - auto iter = mTokenMap.find(tokenId); - if (iter == mTokenMap.end()) { - // Token Id not exist - ALOGD("%s: token #%d not found.", __FUNCTION__, tokenId); - _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr, - /*bufferTraits=*/{}); - return Void(); - } - - const std::vector& tokenHMAC = iter->second.first; - - int numIntsForHMAC = (int)ceil(tokenHMAC.size() * sizeof(uint8_t) / (double)sizeof(int)); - if (tokenHandle->numInts - 1 != numIntsForHMAC) { - // HMAC size not match - ALOGD("%s: token #%d HMAC size not match. Expected: %d Actual: %d", __FUNCTION__, - tokenId, numIntsForHMAC, tokenHandle->numInts - 1); - _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr, - /*bufferTraits=*/{}); - return Void(); - } - - size_t hmacSize = tokenHMAC.size() * sizeof(uint8_t); - if (memcmp(tokenHMAC.data(), &tokenHandle->data[1], hmacSize) != 0) { - // HMAC not match - ALOGD("%s: token #%d HMAC not match.", __FUNCTION__, tokenId); - _hidl_cb(/*status=*/BufferHubStatus::INVALID_TOKEN, /*bufferClient=*/nullptr, - /*bufferTraits=*/{}); - return Void(); - } - - originClientWp = iter->second.second; - mTokenMap.erase(iter); - } - - // Check if original client is dead - sp originClient = originClientWp.promote(); - if (!originClient) { - // Should not happen since token should be removed if already gone - ALOGE("%s: original client %p gone!", __FUNCTION__, originClientWp.unsafe_get()); - _hidl_cb(/*status=*/BufferHubStatus::BUFFER_FREED, /*bufferClient=*/nullptr, - /*bufferTraits=*/{}); - return Void(); - } - - sp client = new BufferClient(*originClient); - uint32_t clientStateMask = client->getBufferNode()->addNewActiveClientsBitToMask(); - if (clientStateMask == 0U) { - // Reach max client count - ALOGE("%s: import failed, BufferNode#%u reached maximum clients.", __FUNCTION__, - client->getBufferNode()->id()); - _hidl_cb(/*status=*/BufferHubStatus::MAX_CLIENT, /*bufferClient=*/nullptr, - /*bufferTraits=*/{}); - return Void(); - } - - std::lock_guard lock(mClientSetMutex); - mClientSet.emplace(client); - - std::shared_ptr node = client->getBufferNode(); - - HardwareBufferDescription bufferDesc; - memcpy(&bufferDesc, &node->bufferDesc(), sizeof(HardwareBufferDescription)); - - // Allocate memory for bufferInfo of type hidl_handle on the stack. See - // http://aosp/286282 for the usage of NATIVE_HANDLE_DECLARE_STORAGE. - NATIVE_HANDLE_DECLARE_STORAGE(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds, - BufferHubDefs::kBufferInfoNumInts); - hidl_handle bufferInfo = buildBufferInfo(bufferInfoStorage, node->id(), clientStateMask, - node->userMetadataSize(), node->metadata().ashmemFd(), - node->eventFd().get()); - BufferTraits bufferTraits = {/*bufferDesc=*/bufferDesc, - /*bufferHandle=*/hidl_handle(node->bufferHandle()), - /*bufferInfo=*/std::move(bufferInfo)}; - - _hidl_cb(/*status=*/BufferHubStatus::NO_ERROR, /*bufferClient=*/client, - /*bufferTraits=*/std::move(bufferTraits)); - return Void(); -} - -Return BufferHubService::debug(const hidl_handle& fd, const hidl_vec& args) { - if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { - ALOGE("%s: missing fd for writing.", __FUNCTION__); - return Void(); - } - - FILE* out = fdopen(dup(fd->data[0]), "w"); - - if (args.size() != 0) { - fprintf(out, - "Note: lshal bufferhub currently does not support args. Input arguments are " - "ignored.\n"); - } - - std::ostringstream stream; - - // Get the number of clients of each buffer. - // Map from bufferId to bufferNode_clientCount pair. - std::map, uint32_t>> clientCount; - { - std::lock_guard lock(mClientSetMutex); - for (auto iter = mClientSet.begin(); iter != mClientSet.end(); ++iter) { - sp client = iter->promote(); - if (client != nullptr) { - const std::shared_ptr node = client->getBufferNode(); - auto mapIter = clientCount.find(node->id()); - if (mapIter != clientCount.end()) { - ++mapIter->second.second; - } else { - clientCount.emplace(node->id(), - std::pair, uint32_t>(node, 1U)); - } - } - } - } - - stream << "Active Buffers:\n"; - stream << std::right; - stream << std::setw(6) << "Id"; - stream << " "; - stream << std::setw(9) << "#Clients"; - stream << " "; - stream << std::setw(14) << "Geometry"; - stream << " "; - stream << std::setw(6) << "Format"; - stream << " "; - stream << std::setw(10) << "Usage"; - stream << " "; - stream << std::setw(10) << "State"; - stream << " "; - stream << std::setw(8) << "Index"; - stream << std::endl; - - for (auto iter = clientCount.begin(); iter != clientCount.end(); ++iter) { - const std::shared_ptr node = std::move(iter->second.first); - const uint32_t clientCount = iter->second.second; - AHardwareBuffer_Desc desc = node->bufferDesc(); - - MetadataHeader* metadataHeader = - const_cast(&node->metadata())->metadataHeader(); - const uint32_t state = metadataHeader->bufferState.load(std::memory_order_acquire); - const uint64_t index = metadataHeader->queueIndex; - - stream << std::right; - stream << std::setw(6) << /*Id=*/node->id(); - stream << " "; - stream << std::setw(9) << /*#Clients=*/clientCount; - stream << " "; - if (desc.format == HAL_PIXEL_FORMAT_BLOB) { - std::string size = std::to_string(desc.width) + " B"; - stream << std::setw(14) << /*Geometry=*/size; - } else { - std::string dimensions = std::to_string(desc.width) + "x" + - std::to_string(desc.height) + "x" + std::to_string(desc.layers); - stream << std::setw(14) << /*Geometry=*/dimensions; - } - stream << " "; - stream << std::setw(6) << /*Format=*/desc.format; - stream << " "; - stream << "0x" << std::hex << std::setfill('0'); - stream << std::setw(8) << /*Usage=*/desc.usage; - stream << std::dec << std::setfill(' '); - stream << " "; - stream << "0x" << std::hex << std::setfill('0'); - stream << std::setw(8) << /*State=*/state; - stream << std::dec << std::setfill(' '); - stream << " "; - stream << std::setw(8) << /*Index=*/index; - stream << std::endl; - } - - stream << std::endl; - - // Get the number of tokens of each buffer. - // Map from bufferId to tokenCount - std::map tokenCount; - { - std::lock_guard lock(mTokenMutex); - for (auto iter = mTokenMap.begin(); iter != mTokenMap.end(); ++iter) { - sp client = iter->second.second.promote(); - if (client != nullptr) { - const std::shared_ptr node = client->getBufferNode(); - auto mapIter = tokenCount.find(node->id()); - if (mapIter != tokenCount.end()) { - ++mapIter->second; - } else { - tokenCount.emplace(node->id(), 1U); - } - } - } - } - - stream << "Unused Tokens:\n"; - stream << std::right; - stream << std::setw(8) << "Buffer Id"; - stream << " "; - stream << std::setw(7) << "#Tokens"; - stream << std::endl; - - for (auto iter = tokenCount.begin(); iter != tokenCount.end(); ++iter) { - stream << std::right; - stream << std::setw(8) << /*Buffer Id=*/iter->first; - stream << " "; - stream << std::setw(7) << /*#Tokens=*/iter->second; - stream << std::endl; - } - - fprintf(out, "%s", stream.str().c_str()); - - fclose(out); - return Void(); -} - -hidl_handle BufferHubService::registerToken(const wp& client) { - // Find next available token id - std::lock_guard lock(mTokenMutex); - do { - ++mLastTokenId; - } while (mTokenMap.find(mLastTokenId) != mTokenMap.end()); - - std::array hmac; - uint32_t hmacSize = 0U; - - HMAC(/*evp_md=*/EVP_sha256(), /*key=*/&mKey, /*key_len=*/kKeyLen, - /*data=*/(uint8_t*)&mLastTokenId, /*data_len=*/mTokenIdSize, - /*out=*/hmac.data(), /*out_len=*/&hmacSize); - - int numIntsForHMAC = (int)ceil(hmacSize / (double)sizeof(int)); - native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1 + numIntsForHMAC); - handle->data[0] = mLastTokenId; - // Set all the the bits of last int to 0 since it might not be fully overwritten - handle->data[numIntsForHMAC] = 0; - memcpy(&handle->data[1], hmac.data(), hmacSize); - - // returnToken owns the native_handle_t* thus doing lifecycle management - hidl_handle returnToken; - returnToken.setTo(handle, /*shoudOwn=*/true); - - std::vector hmacVec; - hmacVec.resize(hmacSize); - memcpy(hmacVec.data(), hmac.data(), hmacSize); - mTokenMap.emplace(mLastTokenId, std::pair(hmacVec, client)); - - return returnToken; -} - -void BufferHubService::onClientClosed(const BufferClient* client) { - removeTokenByClient(client); - - std::lock_guard lock(mClientSetMutex); - auto iter = std::find(mClientSet.begin(), mClientSet.end(), client); - if (iter != mClientSet.end()) { - mClientSet.erase(iter); - } -} - -// Implementation of this function should be consistent with the definition of bufferInfo handle in -// ui/BufferHubDefs.h. -hidl_handle BufferHubService::buildBufferInfo(char* bufferInfoStorage, int bufferId, - uint32_t clientBitMask, uint32_t userMetadataSize, - int metadataFd, int eventFd) { - native_handle_t* infoHandle = - native_handle_init(bufferInfoStorage, BufferHubDefs::kBufferInfoNumFds, - BufferHubDefs::kBufferInfoNumInts); - - infoHandle->data[0] = metadataFd; - infoHandle->data[1] = eventFd; - infoHandle->data[2] = bufferId; - // Use memcpy to convert to int without missing digit. - // TOOD(b/121345852): use bit_cast to unpack bufferInfo when C++20 becomes available. - memcpy(&infoHandle->data[3], &clientBitMask, sizeof(clientBitMask)); - memcpy(&infoHandle->data[4], &userMetadataSize, sizeof(userMetadataSize)); - - hidl_handle bufferInfo; - bufferInfo.setTo(infoHandle, /*shouldOwn=*/false); - - return bufferInfo; -} - -void BufferHubService::removeTokenByClient(const BufferClient* client) { - std::lock_guard lock(mTokenMutex); - auto iter = mTokenMap.begin(); - while (iter != mTokenMap.end()) { - if (iter->second.second == client) { - auto oldIter = iter; - ++iter; - mTokenMap.erase(oldIter); - } else { - ++iter; - } - } -} - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp deleted file mode 100644 index 04ca6493f7..0000000000 --- a/services/bufferhub/BufferNode.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include - -#include -#include -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -void BufferNode::initializeMetadata() { - // Using placement new here to reuse shared memory instead of new allocation - // Initialize the atomic variables to zero. - BufferHubDefs::MetadataHeader* metadataHeader = mMetadata.metadataHeader(); - mBufferState = new (&metadataHeader->bufferState) std::atomic(0); - mFenceState = new (&metadataHeader->fenceState) std::atomic(0); - mActiveClientsBitMask = new (&metadataHeader->activeClientsBitMask) std::atomic(0); - // The C++ standard recommends (but does not require) that lock-free atomic operations are - // also address-free, that is, suitable for communication between processes using shared - // memory. - LOG_ALWAYS_FATAL_IF(!std::atomic_is_lock_free(mBufferState) || - !std::atomic_is_lock_free(mFenceState) || - !std::atomic_is_lock_free(mActiveClientsBitMask), - "Atomic variables in ashmen are not lock free."); -} - -// Allocates a new BufferNode. -BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format, - uint64_t usage, size_t userMetadataSize, int id) - : mId(id) { - uint32_t outStride = 0; - // graphicBufferId is not used in GraphicBufferAllocator::allocate - // TODO(b/112338294) After move to the service folder, stop using the - // hardcoded service name "bufferhub". - int ret = GraphicBufferAllocator::get().allocate(width, height, format, layerCount, usage, - const_cast( - &mBufferHandle), - &outStride, - /*graphicBufferId=*/0, - /*requestor=*/"bufferhub"); - - if (ret != OK || mBufferHandle == nullptr) { - ALOGE("%s: Failed to allocate buffer: %s", __FUNCTION__, strerror(-ret)); - return; - } - - mBufferDesc.width = width; - mBufferDesc.height = height; - mBufferDesc.layers = layerCount; - mBufferDesc.format = format; - mBufferDesc.usage = usage; - mBufferDesc.stride = outStride; - - mMetadata = BufferHubMetadata::create(userMetadataSize); - if (!mMetadata.isValid()) { - ALOGE("%s: Failed to allocate metadata.", __FUNCTION__); - return; - } - initializeMetadata(); -} - -BufferNode::~BufferNode() { - // Free the handle - if (mBufferHandle != nullptr) { - status_t ret = GraphicBufferAllocator::get().free(mBufferHandle); - if (ret != OK) { - ALOGE("%s: Failed to free handle; Got error: %d", __FUNCTION__, ret); - } - } - - // Free the id, if valid - if (mId >= 0) { - BufferHubIdGenerator::getInstance().freeId(mId); - } -} - -uint32_t BufferNode::getActiveClientsBitMask() const { - return mActiveClientsBitMask->load(std::memory_order_acquire); -} - -uint32_t BufferNode::addNewActiveClientsBitToMask() { - uint32_t currentActiveClientsBitMask = getActiveClientsBitMask(); - uint32_t clientStateMask = 0U; - uint32_t updatedActiveClientsBitMask = 0U; - do { - clientStateMask = - BufferHubDefs::findNextAvailableClientStateMask(currentActiveClientsBitMask); - if (clientStateMask == 0U) { - ALOGE("%s: reached the maximum number of channels per buffer node: %d.", __FUNCTION__, - BufferHubDefs::kMaxNumberOfClients); - errno = E2BIG; - return 0U; - } - updatedActiveClientsBitMask = currentActiveClientsBitMask | clientStateMask; - } while (!(mActiveClientsBitMask->compare_exchange_weak(currentActiveClientsBitMask, - updatedActiveClientsBitMask, - std::memory_order_acq_rel, - std::memory_order_acquire))); - return clientStateMask; -} - -void BufferNode::removeClientsBitFromMask(const uint32_t& value) { - mActiveClientsBitMask->fetch_and(~value); -} - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc b/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc deleted file mode 100644 index 36fbedee15..0000000000 --- a/services/bufferhub/android.frameworks.bufferhub@1.0-service.rc +++ /dev/null @@ -1,6 +0,0 @@ -service system_bufferhub /system/bin/hw/android.frameworks.bufferhub@1.0-service - class hal animation - user system - group system graphics - onrestart restart surfaceflinger - writepid /dev/cpuset/system-background/tasks diff --git a/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml b/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml deleted file mode 100644 index bd958d3954..0000000000 --- a/services/bufferhub/android.frameworks.bufferhub@1.0-service.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - android.frameworks.bufferhub - hwbinder - 1.0 - - IBufferHub - default - - - diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h deleted file mode 100644 index 644b40377d..0000000000 --- a/services/bufferhub/include/bufferhub/BufferClient.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H -#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H - -#include - -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -using hardware::hidl_handle; -using hardware::Return; - -// Forward declaration to avoid circular dependency -class BufferHubService; - -class BufferClient : public IBufferClient { -public: - // Creates a server-side buffer client from an existing BufferNode. Note that - // this function takes ownership of the shared_ptr. - // Returns a raw pointer to the BufferClient on success, nullptr on failure. - static BufferClient* create(BufferHubService* service, const std::shared_ptr& node); - - // Creates a BufferClient from an existing BufferClient. Will share the same BufferNode. - explicit BufferClient(const BufferClient& other) - : mService(other.mService), mBufferNode(other.mBufferNode) {} - ~BufferClient(); - - Return close() override; - Return duplicate(duplicate_cb _hidl_cb) override; - - // Non-binder functions - const std::shared_ptr& getBufferNode() const { return mBufferNode; } - -private: - BufferClient(wp service, const std::shared_ptr& node) - : mService(service), mBufferNode(node) {} - - sp getService(); - - wp mService; - - std::mutex mClosedMutex; - bool mClosed GUARDED_BY(mClosedMutex) = false; - - std::shared_ptr mBufferNode; -}; - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android - -#endif diff --git a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h b/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h deleted file mode 100644 index ef7c077feb..0000000000 --- a/services/bufferhub/include/bufferhub/BufferHubIdGenerator.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_ID_GENERATOR_H -#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_ID_GENERATOR_H - -#include -#include - -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -// A thread-safe, non-negative, incremental, int id generator. -class BufferHubIdGenerator { -public: - // Get the singleton instance of this class - static BufferHubIdGenerator& getInstance(); - - // Gets next available id. If next id is greater than std::numeric_limits::max(), it - // will try to get an id start from 0 again. - int getId(); - - // Free a specific id. - void freeId(int id); - -private: - BufferHubIdGenerator() = default; - ~BufferHubIdGenerator() = default; - - // Start from -1 so all valid ids will be >= 0 - int mLastId = -1; - - std::mutex mIdsInUseMutex; - std::set mIdsInUse GUARDED_BY(mIdsInUseMutex); -}; - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android - -#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_ID_GENERATOR_H diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h deleted file mode 100644 index edad20b194..0000000000 --- a/services/bufferhub/include/bufferhub/BufferHubService.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H -#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -using hardware::hidl_handle; -using hardware::hidl_string; -using hardware::hidl_vec; -using hardware::Return; -using hardware::graphics::common::V1_2::HardwareBufferDescription; - -class BufferHubService : public IBufferHub { -public: - BufferHubService(); - - Return allocateBuffer(const HardwareBufferDescription& description, - const uint32_t userMetadataSize, - allocateBuffer_cb _hidl_cb) override; - Return importBuffer(const hidl_handle& tokenHandle, importBuffer_cb _hidl_cb) override; - - Return debug(const hidl_handle& fd, const hidl_vec& args) override; - - // Non-binder functions - // Internal help function for IBufferClient::duplicate. - hidl_handle registerToken(const wp& client); - - void onClientClosed(const BufferClient* client); - -private: - // Helper function to build BufferTraits.bufferInfo handle - hidl_handle buildBufferInfo(char* bufferInfoStorage, int bufferId, uint32_t clientBitMask, - uint32_t userMetadataSize, int metadataFd, int eventFd); - - // Helper function to remove all the token belongs to a specific client. - void removeTokenByClient(const BufferClient* client); - - // List of active BufferClient for bookkeeping. - std::mutex mClientSetMutex; - std::set> mClientSet GUARDED_BY(mClientSetMutex); - - // Token generation related - // A random number used as private key for HMAC - uint64_t mKey; - static constexpr size_t kKeyLen = sizeof(uint64_t); - - std::mutex mTokenMutex; - // The first TokenId will be 1. TokenId could be negative. - int mLastTokenId GUARDED_BY(mTokenMutex) = 0; - static constexpr size_t mTokenIdSize = sizeof(int); - // A map from token id to the token-buffer_client pair. Using token id as the key to reduce - // looking up time - std::map, const wp>> mTokenMap - GUARDED_BY(mTokenMutex); -}; - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android - -#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h deleted file mode 100644 index 62a8d63b38..0000000000 --- a/services/bufferhub/include/bufferhub/BufferNode.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_ -#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_ - -#include -#include -#include -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -class BufferNode { -public: - // Allocates a new BufferNode. - BufferNode(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format, - uint64_t usage, size_t userMetadataSize, int id = -1); - - ~BufferNode(); - - // Returns whether the object holds a valid metadata. - bool isValid() const { return mMetadata.isValid(); } - - int id() const { return mId; } - - size_t userMetadataSize() const { return mMetadata.userMetadataSize(); } - - // Accessors of the buffer description and handle - const native_handle_t* bufferHandle() const { return mBufferHandle; } - const AHardwareBuffer_Desc& bufferDesc() const { return mBufferDesc; } - - // Accessor of event fd. - const BufferHubEventFd& eventFd() const { return mEventFd; } - - // Accessors of mMetadata. - const BufferHubMetadata& metadata() const { return mMetadata; } - - // Gets the current value of mActiveClientsBitMask in mMetadata with - // std::memory_order_acquire, so that all previous releases of - // mActiveClientsBitMask from all threads will be returned here. - uint32_t getActiveClientsBitMask() const; - - // Find and add a new client state mask to mActiveClientsBitMask in - // mMetadata. - // Return the new client state mask that is added to mActiveClientsBitMask. - // Return 0U if there are already 16 clients of the buffer. - uint32_t addNewActiveClientsBitToMask(); - - // Removes the value from active_clients_bit_mask in mMetadata with - // std::memory_order_release, so that the change will be visible to any - // acquire of mActiveClientsBitMask in any threads after the succeed of - // this operation. - void removeClientsBitFromMask(const uint32_t& value); - -private: - // Helper method for constructors to initialize atomic metadata header - // variables in shared memory. - void initializeMetadata(); - - // Gralloc buffer handles. - native_handle_t* mBufferHandle; - AHardwareBuffer_Desc mBufferDesc; - - // Eventfd used for signalling buffer events among the clients of the buffer. - BufferHubEventFd mEventFd; - - // Metadata in shared memory. - BufferHubMetadata mMetadata; - - // A system-unique id generated by bufferhub from 0 to std::numeric_limits::max(). - // BufferNodes not created by bufferhub will have id < 0, meaning "not specified". - // TODO(b/118891412): remove default id = -1 and update comments after pdx is no longer in use - const int mId = -1; - - // The following variables are atomic variables in mMetadata that are visible - // to Bn object and Bp objects. Please find more info in - // BufferHubDefs::MetadataHeader. - - // mBufferState tracks the state of the buffer. Buffer can be in one of these - // four states: gained, posted, acquired, released. - std::atomic* mBufferState = nullptr; - - // TODO(b/112012161): add comments to mFenceState. - std::atomic* mFenceState = nullptr; - - // mActiveClientsBitMask tracks all the bp clients of the buffer. It is the - // union of all client_state_mask of all bp clients. - std::atomic* mActiveClientsBitMask = nullptr; -}; - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android - -#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_ diff --git a/services/bufferhub/main_bufferhub.cpp b/services/bufferhub/main_bufferhub.cpp deleted file mode 100644 index 084460d993..0000000000 --- a/services/bufferhub/main_bufferhub.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include - -using android::sp; -using android::frameworks::bufferhub::V1_0::IBufferHub; -using android::frameworks::bufferhub::V1_0::implementation::BufferHubService; - -int main(int /*argc*/, char** /*argv*/) { - ALOGI("Bootstrap bufferhub HIDL service."); - - android::hardware::configureRpcThreadpool(/*numThreads=*/1, /*willJoin=*/true); - - sp service = new BufferHubService(); - LOG_ALWAYS_FATAL_IF(service->registerAsService() != android::OK, "Failed to register service"); - - android::hardware::joinRpcThreadpool(); - - return 0; -} diff --git a/services/bufferhub/tests/Android.bp b/services/bufferhub/tests/Android.bp deleted file mode 100644 index 3033e705a9..0000000000 --- a/services/bufferhub/tests/Android.bp +++ /dev/null @@ -1,26 +0,0 @@ -cc_test { - name: "BufferHubServer_test", - srcs: [ - "BufferNode_test.cpp", - "BufferHubIdGenerator_test.cpp", - ], - cflags: [ - "-DLOG_TAG=\"BufferHubServer_test\"", - "-DTRACE=0", - "-DATRACE_TAG=ATRACE_TAG_GRAPHICS", - "-Wall", - "-Werror", - ], - compile_multilib: "first", - header_libs: [ - "libdvr_headers", - "libnativewindow_headers", - ], - shared_libs: [ - "libbufferhubservice", - "libui", - ], - static_libs: [ - "libgmock", - ], -} diff --git a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp b/services/bufferhub/tests/BufferHubIdGenerator_test.cpp deleted file mode 100644 index fb6de0d18e..0000000000 --- a/services/bufferhub/tests/BufferHubIdGenerator_test.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -namespace { - -class BufferHubIdGeneratorTest : public testing::Test { -protected: - BufferHubIdGenerator* mIdGenerator = &BufferHubIdGenerator::getInstance(); -}; - -TEST_F(BufferHubIdGeneratorTest, TestGenerateAndFreeID) { - int id = mIdGenerator->getId(); - EXPECT_GE(id, 0); - - mIdGenerator->freeId(id); -} - -TEST_F(BufferHubIdGeneratorTest, TestGenerateUniqueIncrementalID) { - // 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the - // resulting IDs should still keep incresing. - const int kTestSize = 10; - int ids[kTestSize]; - for (int i = 0; i < kTestSize; ++i) { - ids[i] = mIdGenerator->getId(); - EXPECT_GE(ids[i], 0); - if (i >= 1) { - EXPECT_GT(ids[i], ids[i - 1]); - } - } - - for (int i = 0; i < kTestSize; ++i) { - mIdGenerator->freeId(ids[i]); - } -} - -} // namespace - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android \ No newline at end of file diff --git a/services/bufferhub/tests/BufferNode_test.cpp b/services/bufferhub/tests/BufferNode_test.cpp deleted file mode 100644 index 2dfd4fc52e..0000000000 --- a/services/bufferhub/tests/BufferNode_test.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -namespace android { -namespace frameworks { -namespace bufferhub { -namespace V1_0 { -namespace implementation { - -namespace { - -using testing::NotNull; - -const uint32_t kWidth = 640; -const uint32_t kHeight = 480; -const uint32_t kLayerCount = 1; -const uint32_t kFormat = 1; -const uint64_t kUsage = 0; -const size_t kUserMetadataSize = 0; - -class BufferNodeTest : public ::testing::Test { -protected: - void SetUp() override { - mBufferNode = - new BufferNode(kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize); - ASSERT_TRUE(mBufferNode->isValid()); - } - - void TearDown() override { - if (mBufferNode != nullptr) { - delete mBufferNode; - } - } - - BufferNode* mBufferNode = nullptr; -}; - -TEST_F(BufferNodeTest, TestCreateBufferNode) { - EXPECT_EQ(mBufferNode->userMetadataSize(), kUserMetadataSize); - // Test the handle just allocated is good (i.e. able to be imported) - GraphicBufferMapper& mapper = GraphicBufferMapper::get(); - const native_handle_t* outHandle; - status_t ret = - mapper.importBuffer(mBufferNode->bufferHandle(), mBufferNode->bufferDesc().width, - mBufferNode->bufferDesc().height, mBufferNode->bufferDesc().layers, - mBufferNode->bufferDesc().format, mBufferNode->bufferDesc().usage, - mBufferNode->bufferDesc().stride, &outHandle); - EXPECT_EQ(ret, OK); - EXPECT_THAT(outHandle, NotNull()); -} - -TEST_F(BufferNodeTest, TestaddNewActiveClientsBitToMask_twoNewClients) { - uint32_t newClientStateMask1 = mBufferNode->addNewActiveClientsBitToMask(); - EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), newClientStateMask1); - - // Request and add a new client_state_mask again. - // Active clients bit mask should be the union of the two new - // client_state_masks. - uint32_t newClientStateMask2 = mBufferNode->addNewActiveClientsBitToMask(); - EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), newClientStateMask1 | newClientStateMask2); -} - -TEST_F(BufferNodeTest, TestaddNewActiveClientsBitToMask_32NewClients) { - uint32_t newClientStateMask = 0U; - uint32_t currentMask = 0U; - uint32_t expectedMask = 0U; - - for (int i = 0; i < BufferHubDefs::kMaxNumberOfClients; ++i) { - newClientStateMask = mBufferNode->addNewActiveClientsBitToMask(); - EXPECT_NE(newClientStateMask, 0U); - EXPECT_FALSE(newClientStateMask & currentMask); - expectedMask = currentMask | newClientStateMask; - currentMask = mBufferNode->getActiveClientsBitMask(); - EXPECT_EQ(currentMask, expectedMask); - } - - // Method should fail upon requesting for more than maximum allowable clients. - newClientStateMask = mBufferNode->addNewActiveClientsBitToMask(); - EXPECT_EQ(newClientStateMask, 0U); - EXPECT_EQ(errno, E2BIG); -} - -TEST_F(BufferNodeTest, TestRemoveActiveClientsBitFromMask) { - mBufferNode->addNewActiveClientsBitToMask(); - uint32_t currentMask = mBufferNode->getActiveClientsBitMask(); - uint32_t newClientStateMask = mBufferNode->addNewActiveClientsBitToMask(); - EXPECT_NE(mBufferNode->getActiveClientsBitMask(), currentMask); - - mBufferNode->removeClientsBitFromMask(newClientStateMask); - EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), currentMask); - - // Remove the test_mask again to the active client bit mask should not modify - // the value of active clients bit mask. - mBufferNode->removeClientsBitFromMask(newClientStateMask); - EXPECT_EQ(mBufferNode->getActiveClientsBitMask(), currentMask); -} - -} // namespace - -} // namespace implementation -} // namespace V1_0 -} // namespace bufferhub -} // namespace frameworks -} // namespace android -- cgit v1.2.3-59-g8ed1b From 78491e9fd14c44c319efc0e740a862529f26ed47 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Wed, 15 Apr 2020 13:10:56 -0700 Subject: Wait for callbacks before exiting test Bug: 152014889 Test: build, boot, libgui_test Change-Id: I9673933f81b903081d265ed22d0afb71008a6541 --- libs/gui/tests/BLASTBufferQueue_test.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libs') diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index a87ccd664e..d929a59f55 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -722,5 +722,8 @@ TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) { ASSERT_EQ(2, events->frameNumber); ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime); ASSERT_GE(events->postedTime, postedTimeB); + + // wait for any callbacks that have not been received + adapter.waitForCallbacks(); } } // namespace android -- cgit v1.2.3-59-g8ed1b From 2984b7af4f7969cdc02dea6a1722635cc9a432dd Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 13 Apr 2020 17:06:45 -0700 Subject: InputDispatcher: Fix support for INPUT_FEATURE_NO_INPUT_CHANNEL In preparation for an occlusion detection fix, we are going to begin sending windows with NO_INPUT_CHANNEL to InputFlinger. There are 3 obstacles we address here: 1. InputDispatcher ignores windows with no InputChannel when updating input windows. We modify the code to allow such windows if they have INPUT_FEATURE_NO_INPUT_CHANNEL. 2. The parcelling code currently has an optimization to avoid sending the rest of the fields if token is null. We rebase this optimization on whether or not a name is set. 3. InputWindowHandle::getName checks if there is a token to consider the window invalid. We instead check if a name is set. Bug: 152064592 Test: Existing tests pass Change-Id: I8a85f46b6c44866c7f73daafa5e8ff4c9251c366 --- include/input/InputWindow.h | 2 +- libs/input/InputWindow.cpp | 9 ++------- services/inputflinger/dispatcher/InputDispatcher.cpp | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) (limited to 'libs') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index edaf8f530b..a695a8ffda 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -213,7 +213,7 @@ public: } inline std::string getName() const { - return mInfo.token ? mInfo.name : ""; + return !mInfo.name.empty() ? mInfo.name : ""; } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 03ca459fb9..6e4c97ded2 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -65,7 +65,7 @@ bool InputWindowInfo::overlaps(const InputWindowInfo* other) const { } status_t InputWindowInfo::write(Parcel& output) const { - if (token == nullptr) { + if (name.empty()) { output.writeInt32(0); return OK; } @@ -110,12 +110,7 @@ InputWindowInfo InputWindowInfo::read(const Parcel& from) { return ret; } - sp token = from.readStrongBinder(); - if (token == nullptr) { - return ret; - } - - ret.token = token; + ret.token = from.readStrongBinder(); ret.id = from.readInt32(); ret.name = from.readString8().c_str(); ret.layoutParamsFlags = from.readInt32(); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 4ec61b0c63..403e21dffd 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3598,8 +3598,8 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( if (canReceiveInput && !noInputChannel) { ALOGV("Window handle %s has no registered input channel", handle->getName().c_str()); + continue; } - continue; } if (info->displayId != displayId) { -- cgit v1.2.3-59-g8ed1b From b1a4d5836ee3068d8daaa1eec329a71ec2c2bf69 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 16 Apr 2020 16:22:52 -0700 Subject: libbinder: driver unfinished write error code This fatal log used to be hidden inside of a function (Parcel::remove) which always failed, and so when it was removed, the error gained context, but I failed to include other relevant information in the log, such as the error code. Bug: 154144726 Test: m only Change-Id: I477aaee1a335a9faf8c9b249a97c979c08bc4ebf Merged-In: I477aaee1a335a9faf8c9b249a97c979c08bc4ebf --- libs/binder/IPCThreadState.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 9e89c57da3..d67ce15ca9 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -997,7 +997,11 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { if (bwr.write_consumed < mOut.dataSize()) - LOG_ALWAYS_FATAL("Driver did not consume write buffer"); + LOG_ALWAYS_FATAL("Driver did not consume write buffer. " + "err: %s consumed: %zu of %zu", + statusToString(err).c_str(), + (size_t)bwr.write_consumed, + mOut.dataSize()); else { mOut.setDataSize(0); processPostWriteDerefs(); -- cgit v1.2.3-59-g8ed1b From 255acdca7bb9ad76dea94d006238831f66e4e8dd Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 17 Apr 2020 14:08:55 -0700 Subject: BLASTBufferQueue: Don't use mNextTransaction on Binder thread. The "mUseNextTransaction" boolean was intended to ensure that we only used mNextTransaction when calling processBuffer from frameAvailable and not when processing the queue from the transaction callback. However this didn't quite work because we can end up returning early from processNextBuffer() and then the next call (coming from the Transation callback) will use mNextTransaction from the binder thread. If we randomly access mNextTransaction from random threads it's very difficult for other threads to use, so we avoid this directly. Test: Existing tests pass Bug: 153120755 Change-Id: Ic261d1fdf3f1458f208face572f2780c1043192c --- libs/gui/BLASTBufferQueue.cpp | 10 ++++------ libs/gui/include/gui/BLASTBufferQueue.h | 4 +--- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index a8384accce..b0d95214ff 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -189,13 +189,13 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) { mCallbackCV.wait(_lock); } - mUseNextTransaction = true; } // add to shadow queue mNumFrameAvailable++; - processNextBufferLocked(); + processNextBufferLocked(true); } void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) { std::lock_guard _lock{mMutex}; - mUseNextTransaction = false; mNextTransaction = t; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 64c21e0721..b902615adf 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -90,7 +90,7 @@ private: BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs); BLASTBufferQueue(const BLASTBufferQueue& rhs); - void processNextBufferLocked() REQUIRES(mMutex); + void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex); Rect computeCrop(const BufferItem& item); sp mSurfaceControl; @@ -123,8 +123,6 @@ private: sp mBufferItemConsumer; SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex); - - bool mUseNextTransaction = false; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From 8d5688eab29d4e2865720e3e140c2ff613e4032d Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Sat, 18 Apr 2020 00:39:41 -0700 Subject: Pick config based on pixel format. Currently GLESRenderEngine gets a config if EGL_KHR_no_config_context is not supported and uses that config to create dummy surfaces if EGL_KHR_surfaceless_context is not supported. With this patch GLESRenderEngine can pick a config with a different pixel format rather than default to 8 bits per channel. Minor: Remove EGLAttributeVector Bug: b/145968912 Test: atest librenderengine_test Change-Id: If242a72be780ad398643b572ae9fab3840b5084d --- libs/renderengine/gl/GLESRenderEngine.cpp | 84 +++++++++++-------------------- 1 file changed, 28 insertions(+), 56 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 36a54a7464..5c24deeeeb 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -147,52 +147,6 @@ static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EG return NAME_NOT_FOUND; } -class EGLAttributeVector { - struct Attribute; - class Adder; - friend class Adder; - KeyedVector mList; - struct Attribute { - Attribute() : v(0){}; - explicit Attribute(EGLint v) : v(v) {} - EGLint v; - bool operator<(const Attribute& other) const { - // this places EGL_NONE at the end - EGLint lhs(v); - EGLint rhs(other.v); - if (lhs == EGL_NONE) lhs = 0x7FFFFFFF; - if (rhs == EGL_NONE) rhs = 0x7FFFFFFF; - return lhs < rhs; - } - }; - class Adder { - friend class EGLAttributeVector; - EGLAttributeVector& v; - EGLint attribute; - Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {} - - public: - void operator=(EGLint value) { - if (attribute != EGL_NONE) { - v.mList.add(Attribute(attribute), value); - } - } - operator EGLint() const { return v.mList[attribute]; } - }; - -public: - EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); } - void remove(EGLint attribute) { - if (attribute != EGL_NONE) { - mList.removeItem(Attribute(attribute)); - } - } - Adder operator[](EGLint attribute) { return Adder(*this, attribute); } - EGLint operator[](EGLint attribute) const { return mList[attribute]; } - // cast-operator to (EGLint const*) - operator EGLint const*() const { return &mList.keyAt(0).v; } -}; - static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType, EGLConfig* config) { // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if @@ -201,16 +155,33 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint render EGLint wantedAttribute; EGLint wantedAttributeValue; - EGLAttributeVector attribs; + std::vector attribs; if (renderableType) { - attribs[EGL_RENDERABLE_TYPE] = renderableType; - attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE; - attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; - attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE; - attribs[EGL_RED_SIZE] = 8; - attribs[EGL_GREEN_SIZE] = 8; - attribs[EGL_BLUE_SIZE] = 8; - attribs[EGL_ALPHA_SIZE] = 8; + const ui::PixelFormat pixelFormat = static_cast(format); + const bool is1010102 = pixelFormat == ui::PixelFormat::RGBA_1010102; + + // Default to 8 bits per channel. + const EGLint tmpAttribs[] = { + EGL_RENDERABLE_TYPE, + renderableType, + EGL_RECORDABLE_ANDROID, + EGL_TRUE, + EGL_SURFACE_TYPE, + EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + EGL_FRAMEBUFFER_TARGET_ANDROID, + EGL_TRUE, + EGL_RED_SIZE, + is1010102 ? 10 : 8, + EGL_GREEN_SIZE, + is1010102 ? 10 : 8, + EGL_BLUE_SIZE, + is1010102 ? 10 : 8, + EGL_ALPHA_SIZE, + is1010102 ? 2 : 8, + EGL_NONE, + }; + std::copy(tmpAttribs, tmpAttribs + (sizeof(tmpAttribs) / sizeof(EGLint)), + std::back_inserter(attribs)); wantedAttribute = EGL_NONE; wantedAttributeValue = EGL_NONE; } else { @@ -219,7 +190,8 @@ static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint render wantedAttributeValue = format; } - err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config); + err = selectConfigForAttribute(display, attribs.data(), wantedAttribute, wantedAttributeValue, + config); if (err == NO_ERROR) { EGLint caveat; if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat)) -- cgit v1.2.3-59-g8ed1b From fc069ba55fe88ba10d13fdc407fa4704dff64b87 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 20 Apr 2020 13:26:31 -0700 Subject: BufferQueueProducer: Slot may have null buffer I'm not entirely sure how we got in to this state but it seems best not to crash. It seems like we are tearing down and everything will work out in the end anyway. Bug: 153913134 Test: Existing tests pass Change-Id: I1d21fa5f29ca1478ecf8e7cd6363f6f176ae9bee --- libs/gui/BufferQueueProducer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 3f4c5da193..520d0beb43 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -655,8 +655,9 @@ status_t BufferQueueProducer::detachBuffer(int slot) { } listener = mCore->mConsumerListener; - if (listener != nullptr) { - listener->onFrameDetached(mSlots[slot].mGraphicBuffer->getId()); + auto gb = mSlots[slot].mGraphicBuffer; + if (listener != nullptr && gb != nullptr) { + listener->onFrameDetached(gb->getId()); } mSlots[slot].mBufferState.detachProducer(); mCore->mActiveBuffers.erase(slot); -- cgit v1.2.3-59-g8ed1b From 4dde178da6a2d1c4d3130b8319013f8f926d15f7 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 30 Sep 2019 17:27:13 -0700 Subject: [RenderEngine] Rebind output texture when unbinding framebuffer Without this patch, once drawLayers() completes we'd hold onto the backing image data longer than intended since it's bound to sibling texture. This would cause screenshot buffers to be live for longer than intended. This patch rebinds the framebuffer's output texture to a dummy buffer so that we can free memory sooner. We perform this rebind on the main thread in SurfaceFlinger::postComposition, to minimize the amount of expected time we steal for composition due to this cleanup. We also only do this cleanup if the most recent draw fence had fired, since the driver will need to wait for GPU work to complete before freeing resources which can kill performance. Bug: 140158384 Test: screencap and check dumpsys Test: systrace when during screen rotation Test: systrace when toggling GPU composition on and off Test: librenderengine_test, libcompositionengine_test Change-Id: I0aa39e62f03a09f6db000c2abdbb1d0711127fc3 Merged-In: I0aa39e62f03a09f6db000c2abdbb1d0711127fc3 --- libs/renderengine/gl/GLESRenderEngine.cpp | 27 +++++++++++++++- libs/renderengine/gl/GLESRenderEngine.h | 13 +++++++- libs/renderengine/gl/GLFramebuffer.cpp | 4 +-- libs/renderengine/gl/GLFramebuffer.h | 2 +- .../include/renderengine/RenderEngine.h | 8 +++++ .../include/renderengine/mock/RenderEngine.h | 2 ++ libs/renderengine/tests/RenderEngineTest.cpp | 37 +++++++++++++++++++--- services/surfaceflinger/SurfaceFlinger.cpp | 3 ++ 8 files changed, 87 insertions(+), 9 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 36a54a7464..fcaaee948b 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -897,13 +897,32 @@ status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE; } -void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) { +void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /*framebuffer*/) { ATRACE_CALL(); // back to main framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); } +bool GLESRenderEngine::cleanupPostRender() { + ATRACE_CALL(); + + if (mPriorResourcesCleaned || + (mLastDrawFence != nullptr && mLastDrawFence->getStatus() != Fence::Status::Signaled)) { + // If we don't have a prior frame needing cleanup, then don't do anything. + return false; + } + + // Bind the texture to dummy data so that backing image data can be freed. + GLFramebuffer* glFramebuffer = static_cast(getFramebufferForDrawing()); + glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer); + // Release the cached fence here, so that we don't churn reallocations when + // we could no-op repeated calls of this method instead. + mLastDrawFence = nullptr; + mPriorResourcesCleaned = true; + return true; +} + void GLESRenderEngine::checkErrors() const { checkErrors(nullptr); } @@ -1189,7 +1208,13 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, // us bad parameters, or we messed up our shader generation). return INVALID_OPERATION; } + mLastDrawFence = nullptr; + } else { + // The caller takes ownership of drawFence, so we need to duplicate the + // fd here. + mLastDrawFence = new Fence(dup(drawFence->get())); } + mPriorResourcesCleaned = false; checkErrors(); return NO_ERROR; diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 32dbad1050..42b8537b94 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -17,7 +17,6 @@ #ifndef SF_GLESRENDERENGINE_H_ #define SF_GLESRENDERENGINE_H_ -#include #include #include #include @@ -76,6 +75,7 @@ public: const std::vector& layers, ANativeWindowBuffer* buffer, const bool useFramebufferCache, base::unique_fd&& bufferFence, base::unique_fd* drawFence) override; + bool cleanupPostRender() override; EGLDisplay getEGLDisplay() const { return mEGLDisplay; } // Creates an output image for rendering to @@ -231,6 +231,17 @@ private: std::mutex mRenderingMutex; std::unique_ptr mDrawingBuffer; + // this is a 1x1 RGB buffer, but over-allocate in case a driver wants more + // memory or if it needs to satisfy alignment requirements. In this case: + // assume that each channel requires 4 bytes, and add 3 additional bytes to + // ensure that we align on a word. Allocating 16 bytes will provide a + // guarantee that we don't clobber memory. + uint32_t mPlaceholderDrawBuffer[4]; + sp mLastDrawFence; + // Store a separate boolean checking if prior resources were cleaned up, as + // devices that don't support native sync fences can't rely on a last draw + // fence that doesn't exist. + bool mPriorResourcesCleaned = true; // Blur effect processor, only instantiated when a layer requests it. BlurFilter* mBlurFilter = nullptr; diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp index cb0d5cf95c..383486b6b8 100644 --- a/libs/renderengine/gl/GLFramebuffer.cpp +++ b/libs/renderengine/gl/GLFramebuffer.cpp @@ -68,11 +68,11 @@ bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, boo return true; } -void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height) { +void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height, void* data) { ATRACE_CALL(); glBindTexture(GL_TEXTURE_2D, mTextureName); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h index b88da3b133..6757695ddb 100644 --- a/libs/renderengine/gl/GLFramebuffer.h +++ b/libs/renderengine/gl/GLFramebuffer.h @@ -39,7 +39,7 @@ public: bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, const bool useFramebufferCache) override; - void allocateBuffers(uint32_t width, uint32_t height); + void allocateBuffers(uint32_t width, uint32_t height, void* data = nullptr); EGLImageKHR getEGLImage() const { return mEGLImage; } uint32_t getTextureName() const { return mTextureName; } uint32_t getFramebufferName() const { return mFramebufferName; } diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 46f3fc6de0..e06e1287c1 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -111,6 +111,14 @@ public: // Returns NO_ERROR when binds successfully, NO_MEMORY when there's no memory for allocation. virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0; virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0; + // Clean-up method that should be called on the main thread after the + // drawFence returned by drawLayers fires. This method will free up + // resources used by the most recently drawn frame. If the frame is still + // being drawn, then this call is silently ignored. + // + // Returns true if resources were cleaned up, and false if we didn't need to + // do any work. + virtual bool cleanupPostRender() = 0; // queries virtual size_t getMaxTextureSize() const = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 3358c69fb9..df0f17a6d5 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ public: MOCK_CONST_METHOD0(isProtected, bool()); MOCK_CONST_METHOD0(supportsProtectedContent, bool()); MOCK_METHOD1(useProtectedContext, bool(bool)); + MOCK_METHOD0(cleanupPostRender, bool()); MOCK_METHOD6(drawLayers, status_t(const DisplaySettings&, const std::vector&, ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*)); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index f5bf014db1..16a8a0decb 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -1241,12 +1241,12 @@ TEST_F(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) { EXPECT_EQ(NO_ERROR, barrier->result); } -TEST_F(RenderEngineTest, drawLayers_bindExternalBufferWithNullBuffer) { +TEST_F(RenderEngineTest, bindExternalBuffer_withNullBuffer) { status_t result = sRE->bindExternalTextureBuffer(0, nullptr, nullptr); ASSERT_EQ(BAD_VALUE, result); } -TEST_F(RenderEngineTest, drawLayers_bindExternalBufferCachesImages) { +TEST_F(RenderEngineTest, bindExternalBuffer_cachesImages) { sp buf = allocateSourceBuffer(1, 1); uint32_t texName; sRE->genTextures(1, &texName); @@ -1266,7 +1266,7 @@ TEST_F(RenderEngineTest, drawLayers_bindExternalBufferCachesImages) { EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId)); } -TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) { +TEST_F(RenderEngineTest, cacheExternalBuffer_withNullBuffer) { std::shared_ptr barrier = sRE->cacheExternalTextureBufferForTesting(nullptr); std::lock_guard lock(barrier->mutex); @@ -1278,7 +1278,7 @@ TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) { EXPECT_EQ(BAD_VALUE, barrier->result); } -TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) { +TEST_F(RenderEngineTest, cacheExternalBuffer_cachesImages) { sp buf = allocateSourceBuffer(1, 1); uint64_t bufferId = buf->getId(); std::shared_ptr barrier = @@ -1401,6 +1401,35 @@ TEST_F(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) { backgroundColor.a); } +TEST_F(RenderEngineTest, cleanupPostRender_cleansUpOnce) { + renderengine::DisplaySettings settings; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + + std::vector layers; + renderengine::LayerSettings layer; + layer.geometry.boundaries = fullscreenRect().toFloatRect(); + BufferSourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); + layer.alpha = 1.0; + layers.push_back(&layer); + + base::unique_fd fenceOne; + sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, base::unique_fd(), + &fenceOne); + base::unique_fd fenceTwo; + sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true, std::move(fenceOne), + &fenceTwo); + + const int fd = fenceTwo.get(); + if (fd >= 0) { + sync_wait(fd, -1); + } + + // Only cleanup the first time. + EXPECT_TRUE(sRE->cleanupPostRender()); + EXPECT_FALSE(sRE->cleanupPostRender()); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ddf0775c7f..669e37c93e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2311,6 +2311,9 @@ void SurfaceFlinger::postComposition() } getBE().mLastSwapTime = currentTime; + // Cleanup any outstanding resources due to rendering a prior frame. + getRenderEngine().cleanupPostRender(); + { std::lock_guard lock(mTexturePoolMutex); if (mTexturePool.size() < mTexturePoolSize) { -- cgit v1.2.3-59-g8ed1b From a0aeedc3baefdb4c5150a48ed669f063bff8aa8c Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 20 Apr 2020 15:09:35 -0700 Subject: BufferQueueProducer: Slot may have null buffer [2/2]. I'm not entirely sure how we got in to this state but it seems best not to crash. It seems like we are tearing down and everything will work out in the end anyway. This contains the fix to cancelBuffer that was supposed to be in the first CL. Bug: 153913134 Test: Existing tests pass Change-Id: Ie6f17d43e044e18be03e6c477ca8bc0495cee0a1 --- libs/gui/BufferQueueProducer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 3f4c5da193..26784cf14e 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1120,8 +1120,9 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp& fence) { mCore->mFreeBuffers.push_back(slot); } - if (mCore->mConsumerListener != nullptr) { - mCore->mConsumerListener->onFrameCancelled(mSlots[slot].mGraphicBuffer->getId()); + auto gb = mSlots[slot].mGraphicBuffer; + if (mCore->mConsumerListener != nullptr && gb != nullptr) { + mCore->mConsumerListener->onFrameCancelled(gb->getId()); } mSlots[slot].mFence = fence; mCore->mDequeueCondition.notify_all(); -- cgit v1.2.3-59-g8ed1b From 33aa28206531d4bf0117f62f767fd2759bf29931 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Mon, 20 Apr 2020 17:00:30 -0700 Subject: Remove unused method Test: make Fixes: 154550368 Change-Id: I4451d893011150f1f07118fff27380e3d5aaa7d0 --- libs/renderengine/gl/filters/BlurFilter.cpp | 9 --------- libs/renderengine/gl/filters/BlurFilter.h | 1 - 2 files changed, 10 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index 724877bbf6..db55d17aec 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -261,15 +261,6 @@ string BlurFilter::getMixFragShader() const { return shader; } -void BlurFilter::blit(GLFramebuffer& read, GLFramebuffer& draw) const { - ATRACE_NAME("BlurFilter::blit"); - read.bindAsReadBuffer(); - draw.bindAsDrawBuffer(); - glBlitFramebuffer(0, 0, read.getBufferWidth(), read.getBufferHeight(), 0, 0, - draw.getBufferWidth(), draw.getBufferHeight(), GL_COLOR_BUFFER_BIT, - GL_LINEAR); -} - } // namespace gl } // namespace renderengine } // namespace android diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 7e0819fcf9..9d3fc60e48 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -56,7 +56,6 @@ public: private: uint32_t mRadius; void drawMesh(GLuint uv, GLuint position); - void blit(GLFramebuffer& read, GLFramebuffer& draw) const; string getVertexShader() const; string getFragmentShader() const; string getMixFragShader() const; -- cgit v1.2.3-59-g8ed1b From 2f8bdb55482a274f7a7fe3cb87c34014f50fb003 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 19 Apr 2020 21:41:26 -0600 Subject: Offer to write Strings through Parcels as UTF-8. Recently while investigating some Binder limits, I discovered that we're still sending Strings across Binder as UTF-16, which is very wasteful for two reasons: 1. The majority of data flowing through APIs like PackageManager is already limited to US-ASCII, and by sending UTF-16 we're wasting half of our transactions on null-byte overhead. 2. Internally ART is already "compressing" simple strings by storing them as US-ASCII instead of UTF-16, meaning every time we want to write a simple string to Binder, we're forced to first inflate it to UTF-16. This change first updates Parcel.cpp to accept char* UTF-8 strings, similar to how it accepts char16_t* for UTF-16. It then offers both UTF-8 and UTF-16 variants to Parcel.java via JNI. We also update the String8 handling to behave identical to String16. This change adds benchmarking to show that these new methods are about 50% faster for US-ASCII strings, and about 68% faster for complex strings that reference higher Unicode planes. (So an improvement in both cases!) Bug: 154436100 Test: atest FrameworksCoreTests:ParcelTest Test: make core-libart conscrypt okhttp bouncycastle vogar caliper && vogar --mode app_process --benchmark frameworks/base/core/tests/benchmarks/src/android/os/ParcelStringBenchmark.java Change-Id: I3447a0ce28994421977ca50ba8902651f73372f4 --- libs/binder/Parcel.cpp | 72 +++++++++++++++++++++---------------- libs/binder/include/binder/Parcel.h | 2 ++ 2 files changed, 44 insertions(+), 30 deletions(-) (limited to 'libs') diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index beab270387..9642a87f4e 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -987,12 +987,22 @@ status_t Parcel::writeCString(const char* str) status_t Parcel::writeString8(const String8& str) { - status_t err = writeInt32(str.bytes()); - // only write string if its length is more than zero characters, - // as readString8 will only read if the length field is non-zero. - // this is slightly different from how writeString16 works. - if (str.bytes() > 0 && err == NO_ERROR) { - err = write(str.string(), str.bytes()+1); + return writeString8(str.string(), str.size()); +} + +status_t Parcel::writeString8(const char* str, size_t len) +{ + if (str == nullptr) return writeInt32(-1); + + status_t err = writeInt32(len); + if (err == NO_ERROR) { + uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char)); + if (data) { + memcpy(data, str, len); + *reinterpret_cast(data+len) = 0; + return NO_ERROR; + } + err = mError; } return err; } @@ -1832,37 +1842,39 @@ const char* Parcel::readCString() const String8 Parcel::readString8() const { - String8 retString; - status_t status = readString8(&retString); - if (status != OK) { - // We don't care about errors here, so just return an empty string. - return String8(); - } - return retString; + size_t len; + const char* str = readString8Inplace(&len); + if (str) return String8(str, len); + ALOGE("Reading a NULL string not supported here."); + return String8(); } status_t Parcel::readString8(String8* pArg) const { - int32_t size; - status_t status = readInt32(&size); - if (status != OK) { - return status; - } - // watch for potential int overflow from size+1 - if (size < 0 || size >= INT32_MAX) { - return BAD_VALUE; - } - // |writeString8| writes nothing for empty string. - if (size == 0) { + size_t len; + const char* str = readString8Inplace(&len); + if (str) { + pArg->setTo(str, len); + return 0; + } else { *pArg = String8(); - return OK; + return UNEXPECTED_NULL; } - const char* str = (const char*)readInplace(size + 1); - if (str == nullptr) { - return BAD_VALUE; +} + +const char* Parcel::readString8Inplace(size_t* outLen) const +{ + int32_t size = readInt32(); + // watch for potential int overflow from size+1 + if (size >= 0 && size < INT32_MAX) { + *outLen = size; + const char* str = (const char*)readInplace(size+1); + if (str != nullptr) { + return str; + } } - pArg->setTo(str, size); - return OK; + *outLen = 0; + return nullptr; } String16 Parcel::readString16() const diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 4b1a758f38..c1f64fb541 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -119,6 +119,7 @@ public: status_t writeDouble(double val); status_t writeCString(const char* str); status_t writeString8(const String8& str); + status_t writeString8(const char* str, size_t len); status_t writeString16(const String16& str); status_t writeString16(const std::unique_ptr& str); status_t writeString16(const char16_t* str, size_t len); @@ -283,6 +284,7 @@ public: const char* readCString() const; String8 readString8() const; status_t readString8(String8* pArg) const; + const char* readString8Inplace(size_t* outLen) const; String16 readString16() const; status_t readString16(String16* pArg) const; status_t readString16(std::unique_ptr* pArg) const; -- cgit v1.2.3-59-g8ed1b From 27c12feea50ee31f78dfc4d2966517922a608962 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Fri, 6 Mar 2020 10:58:55 -0800 Subject: Fix bugprone-use-after-move warnings Bug: 150783499 Test: TreeHugger Change-Id: I930cbe4b421913a58d7886fbf845a77f94387ff5 Merged-In: I930cbe4b421913a58d7886fbf845a77f94387ff5 --- libs/vr/libpdx_uds/service_endpoint.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp index ecbfdba7c4..9bc70ea9c0 100644 --- a/libs/vr/libpdx_uds/service_endpoint.cpp +++ b/libs/vr/libpdx_uds/service_endpoint.cpp @@ -535,13 +535,13 @@ Status Endpoint::ReceiveMessageForChannel( *message = Message{info}; auto* state = static_cast(message->GetState()); state->request = std::move(request); - if (request.send_len > 0 && !request.is_impulse) { - state->request_data.resize(request.send_len); + if (state->request.send_len > 0 && !state->request.is_impulse) { + state->request_data.resize(state->request.send_len); status = ReceiveData(channel_fd, state->request_data.data(), state->request_data.size()); } - if (status && request.is_impulse) + if (status && state->request.is_impulse) status = ReenableEpollEvent(channel_fd); if (!status) { -- cgit v1.2.3-59-g8ed1b From 9a02eda8d5f95d754aa908e66089750183355511 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 21 Apr 2020 17:39:34 -0700 Subject: Lookup layer handle when registering region sampling listener We must do this in order to prevent clients from providing a bogus handle when registering a region sampling listener. Fortunately, this particular path required a permissions check so it cannot be accessed from arbitrary apps on unrooted devices. But, we should not allow this type of memory corruption to be reachable by the system. Bug: 153467444 Test: libgui_test Test: Repro steps in the bug no longer reproduce Change-Id: I883506798574dfd0688371fdb6305cfad9d153fc --- libs/gui/tests/RegionSampling_test.cpp | 13 ++++++++++++ services/surfaceflinger/RegionSamplingThread.cpp | 7 +------ services/surfaceflinger/RegionSamplingThread.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 23 ++++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 7 ++++++- .../tests/unittests/TestableSurfaceFlinger.h | 1 - .../tests/unittests/TransactionApplicationTest.cpp | 2 +- 7 files changed, 37 insertions(+), 18 deletions(-) (limited to 'libs') diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index dbd4ef9d7e..6746b0a827 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -240,6 +240,19 @@ protected: float const luma_gray = 0.50; }; +TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) { + sp composer = ComposerService::getComposerService(); + sp listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + // Passing in composer service as the layer handle should not crash, we'll + // treat it as a layer that no longer exists and silently allow sampling to + // occur. + status_t status = composer->addRegionSamplingListener(sampleArea, + IInterface::asBinder(composer), listener); + ASSERT_EQ(NO_ERROR, status); + composer->removeRegionSamplingListener(listener); +} + TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) { fill_render(rgba_green); diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 68cd84f661..19c204cddb 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -199,13 +199,8 @@ RegionSamplingThread::~RegionSamplingThread() { } } -void RegionSamplingThread::addListener(const Rect& samplingArea, const sp& stopLayerHandle, +void RegionSamplingThread::addListener(const Rect& samplingArea, const wp& stopLayer, const sp& listener) { - wp stopLayer; - if (stopLayerHandle != nullptr && stopLayerHandle->localBinder() != nullptr) { - stopLayer = static_cast(stopLayerHandle.get())->owner; - } - sp asBinder = IInterface::asBinder(listener); asBinder->linkToDeath(this); std::lock_guard lock(mSamplingMutex); diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 99c07c288e..b9b7a3c436 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -69,7 +69,7 @@ public: // Add a listener to receive luma notifications. The luma reported via listener will // report the median luma for the layers under the stopLayerHandle, in the samplingArea region. - void addListener(const Rect& samplingArea, const sp& stopLayerHandle, + void addListener(const Rect& samplingArea, const wp& stopLayer, const sp& listener); // Remove the listener to stop receiving median luma notifications. void removeListener(const sp& listener); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ddf0775c7f..54b7ef39c2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1449,7 +1449,9 @@ status_t SurfaceFlinger::addRegionSamplingListener(const Rect& samplingArea, if (!listener || samplingArea == Rect::INVALID_RECT) { return BAD_VALUE; } - mRegionSamplingThread->addListener(samplingArea, stopLayerHandle, listener); + + const wp stopLayer = fromHandle(stopLayerHandle); + mRegionSamplingThread->addListener(samplingArea, stopLayer, listener); return NO_ERROR; } @@ -3173,7 +3175,7 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const sp parent; if (parentHandle != nullptr) { - parent = fromHandle(parentHandle); + parent = fromHandleLocked(parentHandle).promote(); if (parent == nullptr) { return NAME_NOT_FOUND; } @@ -3548,7 +3550,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( sp layer = nullptr; if (s.surface) { - layer = fromHandle(s.surface); + layer = fromHandleLocked(s.surface).promote(); } else { // The client may provide us a null handle. Treat it as if the layer was removed. ALOGW("Attempt to set client state with a null layer handle"); @@ -3864,7 +3866,7 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp { Mutex::Autolock _l(mStateLock); - mirrorFrom = fromHandle(mirrorFromHandle); + mirrorFrom = fromHandleLocked(mirrorFromHandle).promote(); if (!mirrorFrom) { return NAME_NOT_FOUND; } @@ -5566,7 +5568,7 @@ status_t SurfaceFlinger::captureLayers( { Mutex::Autolock lock(mStateLock); - parent = fromHandle(layerHandleBinder); + parent = fromHandleLocked(layerHandleBinder).promote(); if (parent == nullptr || parent->isRemovedFromCurrentState()) { ALOGE("captureLayers called with an invalid or removed parent"); return NAME_NOT_FOUND; @@ -5599,7 +5601,7 @@ status_t SurfaceFlinger::captureLayers( reqHeight = crop.height() * frameScale; for (const auto& handle : excludeHandles) { - sp excludeLayer = fromHandle(handle); + sp excludeLayer = fromHandleLocked(handle).promote(); if (excludeLayer != nullptr) { excludeLayers.emplace(excludeLayer); } else { @@ -6062,7 +6064,12 @@ void SurfaceFlinger::SetInputWindowsListener::onSetInputWindowsFinished() { mFlinger->setInputWindowsFinished(); } -sp SurfaceFlinger::fromHandle(const sp& handle) { +wp SurfaceFlinger::fromHandle(const sp& handle) { + Mutex::Autolock _l(mStateLock); + return fromHandleLocked(handle); +} + +wp SurfaceFlinger::fromHandleLocked(const sp& handle) { BBinder* b = nullptr; if (handle) { b = handle->localBinder(); @@ -6072,7 +6079,7 @@ sp SurfaceFlinger::fromHandle(const sp& handle) { } auto it = mLayersByLocalBinderToken.find(b); if (it != mLayersByLocalBinderToken.end()) { - return it->second.promote(); + return it->second; } return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f3c481aa8b..c59d3ff580 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -332,7 +332,12 @@ public: return mTransactionCompletedThread; } - sp fromHandle(const sp& handle) REQUIRES(mStateLock); + // Converts from a binder handle to a Layer + // Returns nullptr if the handle does not point to an existing layer. + // Otherwise, returns a weak reference so that callers off the main-thread + // won't accidentally hold onto the last strong reference. + wp fromHandle(const sp& handle); + wp fromHandleLocked(const sp& handle) REQUIRES(mStateLock); // Inherit from ClientCache::ErasedRecipient void bufferErased(const client_cache_t& clientCacheId) override; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 6995ee0097..319a95984d 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -402,7 +402,6 @@ public: auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; } auto fromHandle(const sp& handle) { - Mutex::Autolock _l(mFlinger->mStateLock); return mFlinger->fromHandle(handle); } diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index f1739e5e8a..65de48c462 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -322,7 +322,7 @@ TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) { TEST_F(TransactionApplicationTest, FromHandle) { sp badHandle; auto ret = mFlinger.fromHandle(badHandle); - EXPECT_EQ(nullptr, ret.get()); + EXPECT_EQ(nullptr, ret.promote().get()); } } // namespace android -- cgit v1.2.3-59-g8ed1b From cedef0560eab55e767bd4a1f433ea30af301d8b7 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 22 Apr 2020 15:58:23 -0700 Subject: BLASTBufferQueue: Don't query for triple buffering Instead accept it as an argument so we can avoid calling property_get_bool over and over. Bug: 152501005 Test: Existing tests pass Change-Id: Ie06ed7940fe883c3182950508c2f3524bf28f702 --- libs/gui/BLASTBufferQueue.cpp | 6 +++--- libs/gui/include/gui/BLASTBufferQueue.h | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index a8384accce..fd838b2b1c 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -95,7 +95,8 @@ void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* ne if (needsDisconnect != nullptr) *needsDisconnect = disconnect; } -BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, int height) +BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, int height, + bool enableTripleBuffering) : mSurfaceControl(surface), mWidth(width), mHeight(height), @@ -105,8 +106,7 @@ BLASTBufferQueue::BLASTBufferQueue(const sp& surface, int width, // explicitly so that dequeueBuffer will block mProducer->setDequeueTimeout(std::numeric_limits::max()); - int8_t disableTripleBuffer = property_get_bool("ro.sf.disable_triple_buffer", 0); - if (!disableTripleBuffer) { + if (enableTripleBuffering) { mProducer->setMaxDequeuedBufferCount(2); } mBufferItemConsumer = diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 64c21e0721..88032c1ec5 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -66,7 +66,9 @@ class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener { public: - BLASTBufferQueue(const sp& surface, int width, int height); + BLASTBufferQueue(const sp& surface, int width, int height, + bool enableTripleBuffering = true); + sp getIGraphicBufferProducer() const { return mProducer; } -- cgit v1.2.3-59-g8ed1b From 5facfb12bea41da2546468b7a1680a606a01e0a6 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 22 Apr 2020 15:18:31 -0700 Subject: SurfaceFlinger: expected present time directly from VSyncReactor When SurfaceFlinger calculates what is the vsync time, it does that by asking VSyncReactor what is next anticipated vsync from the wake up time. To handle negative offsets (when SF wakes up more than a vsync period before a vsync event) SF adds a vsync period to that anticipated vsync. This creates a race condition where the offset used at the time of invalidate may be different than the offset used by VSyncReactor calculated at the time of the requestNextVsync(). To fix that, we plumb the first calculated vsync time to SurfaceFlinger. Bug: 154303002 Test: Run app transitions and collect systrace Change-Id: I3f2670c7b0ecb52a85fb07df6d360694b51d5d66 --- libs/gui/include/gui/DisplayEventReceiver.h | 1 + services/surfaceflinger/RegionSamplingThread.cpp | 2 +- services/surfaceflinger/Scheduler/DispSync.cpp | 33 ++++++++++++++++++---- services/surfaceflinger/Scheduler/DispSync.h | 2 +- .../surfaceflinger/Scheduler/DispSyncSource.cpp | 4 +-- services/surfaceflinger/Scheduler/DispSyncSource.h | 2 +- services/surfaceflinger/Scheduler/EventThread.cpp | 23 +++++++++------ services/surfaceflinger/Scheduler/EventThread.h | 4 +-- .../surfaceflinger/Scheduler/InjectVSyncSource.h | 4 +-- services/surfaceflinger/Scheduler/MessageQueue.cpp | 10 +++---- services/surfaceflinger/Scheduler/MessageQueue.h | 4 +-- services/surfaceflinger/Scheduler/Scheduler.cpp | 4 +-- services/surfaceflinger/Scheduler/Scheduler.h | 2 +- services/surfaceflinger/Scheduler/VSyncReactor.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 25 ++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 7 ++--- .../tests/unittests/DispSyncSourceTest.cpp | 4 +-- .../tests/unittests/EventThreadTest.cpp | 32 ++++++++++----------- .../tests/unittests/VSyncReactorTest.cpp | 6 ++-- .../tests/unittests/mock/MockDispSync.cpp | 6 ++-- 20 files changed, 104 insertions(+), 73 deletions(-) (limited to 'libs') diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 109e28b9dc..d9a0253781 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -65,6 +65,7 @@ public: struct VSync { uint32_t count; + nsecs_t expectedVSyncTimestamp; }; struct Hotplug { diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 68cd84f661..9d293b7887 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -130,7 +130,7 @@ private: mVsyncListening = false; } - void onDispSyncEvent(nsecs_t /* when */) final { + void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) final { std::unique_lock lock(mMutex); if (mPhaseIntervalSetting == Phase::ZERO) { diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index fc6ccaeb6e..ff91bf7bc0 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -200,7 +200,8 @@ public: } } - callbackInvocations = gatherCallbackInvocationsLocked(now); + callbackInvocations = + gatherCallbackInvocationsLocked(now, computeNextRefreshLocked(0, now)); } if (callbackInvocations.size() > 0) { @@ -303,6 +304,11 @@ public: return BAD_VALUE; } + nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const { + Mutex::Autolock lock(mMutex); + return computeNextRefreshLocked(periodOffset, now); + } + private: struct EventListener { const char* mName; @@ -315,6 +321,7 @@ private: struct CallbackInvocation { DispSync::Callback* mCallback; nsecs_t mEventTime; + nsecs_t mExpectedVSyncTime; }; nsecs_t computeNextEventTimeLocked(nsecs_t now) { @@ -340,7 +347,8 @@ private: return duration < (3 * mPeriod) / 5; } - std::vector gatherCallbackInvocationsLocked(nsecs_t now) { + std::vector gatherCallbackInvocationsLocked(nsecs_t now, + nsecs_t expectedVSyncTime) { if (mTraceDetailedInfo) ATRACE_CALL(); ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now)); @@ -361,6 +369,10 @@ private: CallbackInvocation ci; ci.mCallback = eventListener.mCallback; ci.mEventTime = t; + ci.mExpectedVSyncTime = expectedVSyncTime; + if (eventListener.mPhase < 0) { + ci.mExpectedVSyncTime += mPeriod; + } ALOGV("[%s] [%s] Preparing to fire, latency: %" PRId64, mName, eventListener.mName, t - eventListener.mLastEventTime); callbackInvocations.push_back(ci); @@ -426,8 +438,17 @@ private: void fireCallbackInvocations(const std::vector& callbacks) { if (mTraceDetailedInfo) ATRACE_CALL(); for (size_t i = 0; i < callbacks.size(); i++) { - callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime); + callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime, + callbacks[i].mExpectedVSyncTime); + } + } + + nsecs_t computeNextRefreshLocked(int periodOffset, nsecs_t now) const { + nsecs_t phase = mReferenceTime + mPhase; + if (mPeriod == 0) { + return 0; } + return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase; } const char* const mName; @@ -444,7 +465,7 @@ private: std::vector mEventListeners; - Mutex mMutex; + mutable Mutex mMutex; Condition mCond; // Flag to turn on logging in systrace. @@ -458,7 +479,7 @@ class ZeroPhaseTracer : public DispSync::Callback { public: ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {} - virtual void onDispSyncEvent(nsecs_t /*when*/) { + virtual void onDispSyncEvent(nsecs_t /*when*/, nsecs_t /*expectedVSyncTimestamp*/) { mParity = !mParity; } @@ -845,7 +866,7 @@ nsecs_t DispSync::expectedPresentTime(nsecs_t now) { const uint32_t hwcLatency = 0; // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC). - return computeNextRefresh(hwcLatency, now); + return mThread->computeNextRefresh(hwcLatency, now); } } // namespace impl diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h index 2faa81ce41..832f08e07b 100644 --- a/services/surfaceflinger/Scheduler/DispSync.h +++ b/services/surfaceflinger/Scheduler/DispSync.h @@ -36,7 +36,7 @@ public: public: Callback() = default; virtual ~Callback(); - virtual void onDispSyncEvent(nsecs_t when) = 0; + virtual void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0; protected: Callback(Callback const&) = delete; diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 4e3f85f53e..8752b6600e 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -92,7 +92,7 @@ void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { } } -void DispSyncSource::onDispSyncEvent(nsecs_t when) { +void DispSyncSource::onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) { VSyncSource::Callback* callback; { std::lock_guard lock(mCallbackMutex); @@ -104,7 +104,7 @@ void DispSyncSource::onDispSyncEvent(nsecs_t when) { } if (callback != nullptr) { - callback->onVSyncEvent(when); + callback->onVSyncEvent(when, expectedVSyncTimestamp); } } diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index f278712407..2aee3f6321 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -40,7 +40,7 @@ public: private: // The following method is the implementation of the DispSync::Callback. - virtual void onDispSyncEvent(nsecs_t when); + void onDispSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override; const char* const mName; TracedOrdinal mValue; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 8347650636..5dedb6a1e7 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -79,8 +79,9 @@ std::string toString(const DisplayEventReceiver::Event& event) { event.hotplug.connected ? "connected" : "disconnected"); case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT - ", count=%u}", - event.header.displayId, event.vsync.count); + ", count=%u, expectedVSyncTimestamp=%" PRId64 "}", + event.header.displayId, event.vsync.count, + event.vsync.expectedVSyncTimestamp); case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%u}", @@ -99,10 +100,11 @@ DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t tim } DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp, - uint32_t count) { + uint32_t count, nsecs_t expectedVSyncTimestamp) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp}; event.vsync.count = count; + event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp; return event; } @@ -312,11 +314,12 @@ void EventThread::onScreenAcquired() { mCondition.notify_all(); } -void EventThread::onVSyncEvent(nsecs_t timestamp) { +void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) { std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); - mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count)); + mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, + expectedVSyncTimestamp)); mCondition.notify_all(); } @@ -423,7 +426,8 @@ void EventThread::threadMain(std::unique_lock& lock) { } else { // Generate a fake VSYNC after a long timeout in case the driver stalls. When the // display is off, keep feeding clients at 60 Hz. - const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms; + const std::chrono::nanoseconds timeout = + mState == State::SyntheticVSync ? 16ms : 1000ms; if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) { if (mState == State::VSync) { ALOGW("Faking VSYNC due to driver stall for thread %s", mThreadName); @@ -439,9 +443,10 @@ void EventThread::threadMain(std::unique_lock& lock) { } LOG_FATAL_IF(!mVSyncState); - mPendingEvents.push_back(makeVSync(mVSyncState->displayId, - systemTime(SYSTEM_TIME_MONOTONIC), - ++mVSyncState->count)); + const auto now = systemTime(SYSTEM_TIME_MONOTONIC); + const auto expectedVSyncTime = now + timeout.count(); + mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now, + ++mVSyncState->count, expectedVSyncTime)); } } } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 98b1876994..9e7086eb0c 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -57,7 +57,7 @@ public: class Callback { public: virtual ~Callback() {} - virtual void onVSyncEvent(nsecs_t when) = 0; + virtual void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) = 0; }; virtual ~VSyncSource() {} @@ -189,7 +189,7 @@ private: REQUIRES(mMutex); // Implements VSyncSource::Callback - void onVSyncEvent(nsecs_t timestamp) override; + void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp) override; const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h index 31da588b72..975c9db41a 100644 --- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h +++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h @@ -35,10 +35,10 @@ public: mCallback = callback; } - void onInjectSyncEvent(nsecs_t when) { + void onInjectSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) { std::lock_guard lock(mCallbackMutex); if (mCallback) { - mCallback->onVSyncEvent(when); + mCallback->onVSyncEvent(when, expectedVSyncTimestamp); } } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index d8a666a6de..9d6e1d864a 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -62,9 +62,9 @@ void MessageQueue::Handler::dispatchRefresh() { } } -void MessageQueue::Handler::dispatchInvalidate(nsecs_t timestamp) { +void MessageQueue::Handler::dispatchInvalidate(nsecs_t expectedVSyncTimestamp) { if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) { - mLastVsyncTime = timestamp; + mExpectedVSyncTime = expectedVSyncTimestamp; mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE)); } } @@ -73,11 +73,11 @@ void MessageQueue::Handler::handleMessage(const Message& message) { switch (message.what) { case INVALIDATE: android_atomic_and(~eventMaskInvalidate, &mEventMask); - mQueue.mFlinger->onMessageReceived(message.what, mLastVsyncTime); + mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime); break; case REFRESH: android_atomic_and(~eventMaskRefresh, &mEventMask); - mQueue.mFlinger->onMessageReceived(message.what, mLastVsyncTime); + mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime); break; } } @@ -152,7 +152,7 @@ int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) { while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) { for (int i = 0; i < n; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - mHandler->dispatchInvalidate(buffer[i].header.timestamp); + mHandler->dispatchInvalidate(buffer[i].vsync.expectedVSyncTimestamp); break; } } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index dbd5e96f00..ebc4315ec9 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -101,13 +101,13 @@ class MessageQueue final : public android::MessageQueue { enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 }; MessageQueue& mQueue; int32_t mEventMask; - std::atomic mLastVsyncTime; + std::atomic mExpectedVSyncTime; public: explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {} virtual void handleMessage(const Message& message); void dispatchRefresh(); - void dispatchInvalidate(nsecs_t timestamp); + void dispatchInvalidate(nsecs_t expectedVSyncTimestamp); }; friend class Handler; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 3a84b67e93..86bb6eb7de 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -276,12 +276,12 @@ Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { return mInjectorConnectionHandle; } -bool Scheduler::injectVSync(nsecs_t when) { +bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime) { if (!mInjectVSyncs || !mVSyncInjector) { return false; } - mVSyncInjector->onInjectSyncEvent(when); + mVSyncInjector->onInjectSyncEvent(when, expectedVSyncTime); return true; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 75c02f3134..4a0280fe1e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -95,7 +95,7 @@ public: ConnectionHandle enableVSyncInjection(bool enable); // Returns false if injection is disabled. - bool injectVSync(nsecs_t when); + bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime); void enableHardwareVsync(); void disableHardwareVsync(bool makeUnavailable); diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index 2f1faacba0..5f0c9ce40c 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -128,7 +128,7 @@ private: mLastCallTime = vsynctime; } - mCallback->onDispSyncEvent(wakeupTime); + mCallback->onDispSyncEvent(wakeupTime, vsynctime); { std::lock_guard lk(mMutex); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4a71295c34..a6e1e69cc8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1415,7 +1415,7 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { status_t SurfaceFlinger::injectVSync(nsecs_t when) { Mutex::Autolock lock(mStateLock); - return mScheduler->injectVSync(when) ? NO_ERROR : BAD_VALUE; + return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE; } status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) const @@ -1824,16 +1824,16 @@ nsecs_t SurfaceFlinger::previousFramePresentTime() NO_THREAD_SAFETY_ANALYSIS { return fence->getSignalTime(); } -void SurfaceFlinger::populateExpectedPresentTime(nsecs_t wakeupTime) { +nsecs_t SurfaceFlinger::calculateExpectedPresentTime(nsecs_t now) const { DisplayStatInfo stats; mScheduler->getDisplayStatInfo(&stats); - const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(wakeupTime); + const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(now); // Inflate the expected present time if we're targetting the next vsync. - mExpectedPresentTime.store( - mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod); + return mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod; } -void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t when) NO_THREAD_SAFETY_ANALYSIS { +void SurfaceFlinger::onMessageReceived(int32_t what, + nsecs_t expectedVSyncTime) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { @@ -1842,7 +1842,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t when) NO_THREAD_SAF // value throughout this frame to make sure all layers are // seeing this same value. const nsecs_t lastExpectedPresentTime = mExpectedPresentTime.load(); - populateExpectedPresentTime(when); + mExpectedPresentTime = expectedVSyncTime; // When Backpressure propagation is enabled we want to give a small grace period // for the present fence to fire instead of just giving up on this frame to handle cases @@ -3239,7 +3239,6 @@ bool SurfaceFlinger::flushTransactionQueues() { while (!transactionQueue.empty()) { const auto& transaction = transactionQueue.front(); if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime, - true /* useCachedExpectedPresentTime */, transaction.states)) { setTransactionFlags(eTransactionFlushNeeded); break; @@ -3271,9 +3270,7 @@ bool SurfaceFlinger::transactionFlushNeeded() { bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, - bool useCachedExpectedPresentTime, const Vector& states) { - if (!useCachedExpectedPresentTime) populateExpectedPresentTime(systemTime()); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second @@ -3325,9 +3322,13 @@ void SurfaceFlinger::setTransactionState( } } + const bool pendingTransactions = itr != mTransactionQueues.end(); // Expected present time is computed and cached on invalidate, so it may be stale. - if (itr != mTransactionQueues.end() || !transactionIsReadyToBeApplied( - desiredPresentTime, false /* useCachedExpectedPresentTime */, states)) { + if (!pendingTransactions) { + mExpectedPresentTime = calculateExpectedPresentTime(systemTime()); + } + + if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) { mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 484e3ed601..7f6c260633 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -315,7 +315,7 @@ public: // called on the main thread by MessageQueue when an internal message // is received // TODO: this should be made accessible only to MessageQueue - void onMessageReceived(int32_t what, nsecs_t when); + void onMessageReceived(int32_t what, nsecs_t expectedVSyncTime); renderengine::RenderEngine& getRenderEngine() const; @@ -625,7 +625,6 @@ private: void commitTransaction() REQUIRES(mStateLock); void commitOffscreenLayers(); bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, - bool useCachedExpectedPresentTime, const Vector& states); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) @@ -847,9 +846,9 @@ private: // Must be called on the main thread. nsecs_t previousFramePresentTime(); - // Populates the expected present time for this frame. For negative offsets, performs a + // Calculates the expected present time for this frame. For negative offsets, performs a // correction using the predicted vsync for the next frame instead. - void populateExpectedPresentTime(nsecs_t now); + nsecs_t calculateExpectedPresentTime(nsecs_t now) const; /* * Display identification diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 2e705dad6d..afebc40aa9 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -43,7 +43,7 @@ protected: void createDispSync(); void createDispSyncSource(); - void onVSyncEvent(nsecs_t when) override; + void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override; std::unique_ptr mDispSync; std::unique_ptr mDispSyncSource; @@ -66,7 +66,7 @@ DispSyncSourceTest::~DispSyncSourceTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -void DispSyncSourceTest::onVSyncEvent(nsecs_t when) { +void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) { ALOGD("onVSyncEvent: %" PRId64, when); mVSyncEventCallRecorder.recordCall(when); diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index ba5c0c2988..b90b566eee 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -258,14 +258,14 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { // Use the received callback to signal a first vsync event. // The interceptor should receive the event, as well as the connection. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection(123, 1u); // Use the received callback to signal a second vsync event. // The interceptor should receive the event, but the the connection should // not as it was only interested in the first. - mCallback->onVSyncEvent(456); + mCallback->onVSyncEvent(456, 123); expectInterceptCallReceived(456); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); @@ -299,7 +299,7 @@ TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Send a vsync event. EventThread should then make a call to the // interceptor, and the second connection. The first connection should not // get the event. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value()); expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123, @@ -314,17 +314,17 @@ TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) { // Send a vsync event. EventThread should then make a call to the // interceptor, and the connection. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection(123, 1u); // A second event should go to the same places. - mCallback->onVSyncEvent(456); + mCallback->onVSyncEvent(456, 123); expectInterceptCallReceived(456); expectVsyncEventReceivedByConnection(456, 2u); // A third event should go to the same places. - mCallback->onVSyncEvent(789); + mCallback->onVSyncEvent(789, 777); expectInterceptCallReceived(789); expectVsyncEventReceivedByConnection(789, 3u); } @@ -336,22 +336,22 @@ TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) { expectVSyncSetEnabledCallReceived(true); // The first event will be seen by the interceptor, and not the connection. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); // The second event will be seen by the interceptor and the connection. - mCallback->onVSyncEvent(456); + mCallback->onVSyncEvent(456, 123); expectInterceptCallReceived(456); expectVsyncEventReceivedByConnection(456, 2u); // The third event will be seen by the interceptor, and not the connection. - mCallback->onVSyncEvent(789); + mCallback->onVSyncEvent(789, 777); expectInterceptCallReceived(789); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); // The fourth event will be seen by the interceptor and the connection. - mCallback->onVSyncEvent(101112); + mCallback->onVSyncEvent(101112, 7847); expectInterceptCallReceived(101112); expectVsyncEventReceivedByConnection(101112, 4u); } @@ -366,7 +366,7 @@ TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) { mConnection = nullptr; // The first event will be seen by the interceptor, and not the connection. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value()); @@ -386,13 +386,13 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { // The first event will be seen by the interceptor, and by the connection, // which then returns an error. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); // A subsequent event will be seen by the interceptor and not by the // connection. - mCallback->onVSyncEvent(456); + mCallback->onVSyncEvent(456, 123); expectInterceptCallReceived(456); EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value()); @@ -420,7 +420,7 @@ TEST_F(EventThreadTest, tracksEventConnections) { // The first event will be seen by the interceptor, and by the connection, // which then returns an error. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123, @@ -440,13 +440,13 @@ TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { // The first event will be seen by the interceptor, and by the connection, // which then returns an non-fatal error. - mCallback->onVSyncEvent(123); + mCallback->onVSyncEvent(123, 456); expectInterceptCallReceived(123); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); // A subsequent event will be seen by the interceptor, and by the connection, // which still then returns an non-fatal error. - mCallback->onVSyncEvent(456); + mCallback->onVSyncEvent(456, 123); expectInterceptCallReceived(456); expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u); diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index 32c9045ade..3f14d652ce 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -135,7 +135,7 @@ std::shared_ptr generateSignalledFenceWithTime(nsecs_t time) { class StubCallback : public DispSync::Callback { public: - void onDispSyncEvent(nsecs_t when) final { + void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final { std::lock_guard lk(mMutex); mLastCallTime = when; } @@ -544,7 +544,9 @@ TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) { class SelfRemovingCallback : public DispSync::Callback { public: SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {} - void onDispSyncEvent(nsecs_t when) final { mVsr.removeEventListener(this, &when); } + void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final { + mVsr.removeEventListener(this, &when); + } private: VSyncReactor& mVsr; diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp index f6c4f62022..1c8c44dca0 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp +++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp @@ -17,6 +17,7 @@ #include "mock/MockDispSync.h" #include +using namespace std::chrono_literals; namespace android { namespace mock { @@ -54,8 +55,9 @@ status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) { void DispSync::triggerCallback() { if (mCallback.callback == nullptr) return; - mCallback.callback->onDispSyncEvent( - std::chrono::steady_clock::now().time_since_epoch().count()); + const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch(); + const auto expectedVSyncTime = now + 16ms; + mCallback.callback->onDispSyncEvent(now.count(), expectedVSyncTime.count()); } } // namespace mock -- cgit v1.2.3-59-g8ed1b From f33c9f1e5f3996161fd37d941016403537ad6ecf Mon Sep 17 00:00:00 2001 From: Sundong Ahn Date: Thu, 23 Apr 2020 21:31:20 +0900 Subject: Change to using sysprop for libgui_tests The configstore service was deprecated. So change to use sysprop instead of configstore Bug: 124531214 Test: atest SurfaceTest#CreateSurfaceReturnsErrorBadClient && check reading property values Change-Id: I1825a304c4fe40e3ef9f54e1e8fef05b1f9a2e8f Merged-In: I1825a304c4fe40e3ef9f54e1e8fef05b1f9a2e8f (cherry picked from commit e6e7d44e712dea650c27f8fa7f1a183d504d9b0a) --- libs/gui/tests/Android.bp | 3 +++ libs/gui/tests/Surface_test.cpp | 9 ++++----- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 7f960abb35..a6bcd107af 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -39,6 +39,7 @@ cc_test { shared_libs: [ "android.hardware.configstore@1.0", "android.hardware.configstore-utils", + "libSurfaceFlingerProp", "libbase", "liblog", "libEGL", @@ -53,6 +54,8 @@ cc_test { "libutils", "libnativewindow" ], + + header_libs: ["libsurfaceflinger_headers"], } // Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 2de6b69659..d1d770e542 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -18,17 +18,18 @@ #include +#include #include #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -46,11 +47,9 @@ using ui::ColorMode; using Transaction = SurfaceComposerClient::Transaction; -static bool hasWideColorDisplay = - getBool(false); +static bool hasWideColorDisplay = android::sysprop::has_wide_color_display(false); -static bool hasHdrDisplay = - getBool(false); +static bool hasHdrDisplay = android::sysprop::has_HDR_display(false); class FakeSurfaceComposer; class FakeProducerFrameEventHistory; -- cgit v1.2.3-59-g8ed1b From f7f7cde49dbdfddd8b4dbb240d0bc87f4002c4b3 Mon Sep 17 00:00:00 2001 From: Sundong Ahn Date: Thu, 23 Apr 2020 21:43:55 +0900 Subject: Change to using sysprop for vrflinger_test The configstore service was deprecated. So change to use sysprop instead of configstore. Bug: 124531214 Test: m -j Change-Id: I5367b5715c797facd37736eee84651addbaa230d Merged-In: I5367b5715c797facd37736eee84651addbaa230d (cherry picked from commit 8e852f5231d34b80a19aa5cceb0c8fec06fb3236) --- libs/vr/libvrflinger/tests/Android.bp | 2 ++ libs/vr/libvrflinger/tests/vrflinger_test.cpp | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp index 410e2344ce..7fafd3bf50 100644 --- a/libs/vr/libvrflinger/tests/Android.bp +++ b/libs/vr/libvrflinger/tests/Android.bp @@ -11,6 +11,7 @@ shared_libs = [ "libutils", "libnativewindow", "libpdx_default_transport", + "libSurfaceFlingerProp", ] static_libs = [ @@ -32,5 +33,6 @@ cc_test { "-Wall", "-Werror", ], + header_libs: ["libsurfaceflinger_headers"], name: "vrflinger_test", } diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp index 7075e88267..efd6d1dcd7 100644 --- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp +++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -147,9 +148,7 @@ TEST(VrFlingerTest, ActivateDeactivate) { // Exit immediately if the device doesn't support vr flinger. This ConfigStore // check is the same mechanism used by surface flinger to decide if it should // initialize vr flinger. - bool vr_flinger_enabled = - getBool( - false); + bool vr_flinger_enabled = android::sysprop::use_vr_flinger(false); if (!vr_flinger_enabled) { return; } -- cgit v1.2.3-59-g8ed1b From 3d61bc1e6260f227a15d10c72240124207df3861 Mon Sep 17 00:00:00 2001 From: Edgar Arriaga Date: Thu, 16 Apr 2020 18:46:48 -0700 Subject: Optimization: Restrict signing to ACTION_UP and ACTION_DOWN while doing a motion gesture such as scrolling apps Savings. ~2.5% of total system_server time while scrolling on apps drawer screen. Baseline: https://pprof.corp.google.com/?id=732307aa60aa82bf478b0c3f0e6de6be&ignore=sendMessage https://screenshot.googleplex.com/JpWt25tXRJO Optimized: https://pprof.corp.google.com/?id=5040d255411f407662a7f2da0109ca48&ignore=sendMessage https://screenshot.googleplex.com/x81k7vUUKdd Test: atest inputflinger_tests Bug: 154278518 Merged-In: I52dd33f8203fe62bfcbde7be5a1ac45c46064585 Change-Id: I52dd33f8203fe62bfcbde7be5a1ac45c46064585 (cherry picked from commit c6ae4bbc44183811ad84abf5abc56a96843545bc) --- libs/input/InputTransport.cpp | 4 +- .../inputflinger/dispatcher/InputDispatcher.cpp | 47 ++++++++++++++-------- services/inputflinger/dispatcher/InputDispatcher.h | 8 +++- 3 files changed, 38 insertions(+), 21 deletions(-) (limited to 'libs') diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index ef7cc7d531..11af23e1a2 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -468,7 +468,7 @@ status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.displayId = displayId; - msg.body.key.hmac = hmac; + msg.body.key.hmac = std::move(hmac); msg.body.key.action = action; msg.body.key.flags = flags; msg.body.key.keyCode = keyCode; @@ -526,7 +526,7 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.displayId = displayId; - msg.body.motion.hmac = hmac; + msg.body.motion.hmac = std::move(hmac); msg.body.motion.action = action; msg.body.motion.actionButton = actionButton; msg.body.motion.flags = flags; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6a45d58f57..56d65670ed 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -352,18 +352,16 @@ std::array HmacKeyManager::sign(const VerifiedInputEvent& event) co break; } } - std::vector data; const uint8_t* start = reinterpret_cast(&event); - data.assign(start, start + size); - return sign(data); + return sign(start, size); } -std::array HmacKeyManager::sign(const std::vector& data) const { +std::array HmacKeyManager::sign(const uint8_t* data, size_t size) const { // SHA256 always generates 32-bytes result std::array hash; unsigned int hashLen = 0; - uint8_t* result = HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data.data(), data.size(), - hash.data(), &hashLen); + uint8_t* result = + HMAC(EVP_sha256(), mHmacKey.data(), mHmacKey.size(), data, size, hash.data(), &hashLen); if (result == nullptr) { ALOGE("Could not sign the data using HMAC"); return INVALID_HMAC; @@ -2451,11 +2449,8 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::Type::KEY: { - KeyEntry* keyEntry = static_cast(eventEntry); - VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(*keyEntry); - verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_KEY_EVENT_FLAGS; - verifiedEvent.action = dispatchEntry->resolvedAction; - std::array hmac = mHmacKeyManager.sign(verifiedEvent); + const KeyEntry* keyEntry = static_cast(eventEntry); + std::array hmac = getSignature(*keyEntry, *dispatchEntry); // Publish the key event. status = @@ -2507,12 +2502,8 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, usingCoords = scaledCoords; } } - VerifiedMotionEvent verifiedEvent = - verifiedMotionEventFromMotionEntry(*motionEntry); - verifiedEvent.actionMasked = - dispatchEntry->resolvedAction & AMOTION_EVENT_ACTION_MASK; - verifiedEvent.flags = dispatchEntry->resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS; - std::array hmac = mHmacKeyManager.sign(verifiedEvent); + + std::array hmac = getSignature(*motionEntry, *dispatchEntry); // Publish the motion event. status = connection->inputPublisher @@ -2592,6 +2583,28 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } } +const std::array InputDispatcher::getSignature( + const MotionEntry& motionEntry, const DispatchEntry& dispatchEntry) const { + int32_t actionMasked = dispatchEntry.resolvedAction & AMOTION_EVENT_ACTION_MASK; + if ((actionMasked == AMOTION_EVENT_ACTION_UP) || (actionMasked == AMOTION_EVENT_ACTION_DOWN)) { + // Only sign events up and down events as the purely move events + // are tied to their up/down counterparts so signing would be redundant. + VerifiedMotionEvent verifiedEvent = verifiedMotionEventFromMotionEntry(motionEntry); + verifiedEvent.actionMasked = actionMasked; + verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_MOTION_EVENT_FLAGS; + return mHmacKeyManager.sign(verifiedEvent); + } + return INVALID_HMAC; +} + +const std::array InputDispatcher::getSignature( + const KeyEntry& keyEntry, const DispatchEntry& dispatchEntry) const { + VerifiedKeyEvent verifiedEvent = verifiedKeyEventFromKeyEntry(keyEntry); + verifiedEvent.flags = dispatchEntry.resolvedFlags & VERIFIED_KEY_EVENT_FLAGS; + verifiedEvent.action = dispatchEntry.resolvedAction; + return mHmacKeyManager.sign(verifiedEvent); +} + void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index cbba7e1318..2b9cbcec2e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -62,7 +62,7 @@ public: std::array sign(const VerifiedInputEvent& event) const; private: - std::array sign(const std::vector& data) const; + std::array sign(const uint8_t* data, size_t size) const; const std::array mHmacKey; }; @@ -219,7 +219,11 @@ private: // the pointer stream in order to claim it for a system gesture. std::unordered_map> mGestureMonitorsByDisplay GUARDED_BY(mLock); - HmacKeyManager mHmacKeyManager; + const HmacKeyManager mHmacKeyManager; + const std::array getSignature(const MotionEntry& motionEntry, + const DispatchEntry& dispatchEntry) const; + const std::array getSignature(const KeyEntry& keyEntry, + const DispatchEntry& dispatchEntry) const; // Event injection and synchronization. std::condition_variable mInjectionResultAvailable; -- cgit v1.2.3-59-g8ed1b From 547808b38c83f071438a4677f75860228b30b075 Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Thu, 2 Apr 2020 09:31:08 -0700 Subject: Fast path Region::orSelf when empty If a Region is empty, orSelf is equivalent to just assigning from the other Region/Rect, so we don't need to perform a whole rasterization pass. Test: libsurfaceflinger_unittest Test: simpleperf measurement of SF shows workload reduction Bug: 153112939 Change-Id: Iefa0e0177a0e85ce72e37842885d3c8b68ce6025 --- libs/ui/Region.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'libs') diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index bf487c4aec..d929cc30ba 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -306,6 +306,10 @@ void Region::addRectUnchecked(int l, int t, int r, int b) // ---------------------------------------------------------------------------- Region& Region::orSelf(const Rect& r) { + if (isEmpty()) { + set(r); + return *this; + } return operationSelf(r, op_or); } Region& Region::xorSelf(const Rect& r) { @@ -326,6 +330,10 @@ Region& Region::operationSelf(const Rect& r, uint32_t op) { // ---------------------------------------------------------------------------- Region& Region::orSelf(const Region& rhs) { + if (isEmpty()) { + *this = rhs; + return *this; + } return operationSelf(rhs, op_or); } Region& Region::xorSelf(const Region& rhs) { -- cgit v1.2.3-59-g8ed1b From bfc95966e74f3b04e4c70e283dd8d281c71de6bb Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Tue, 28 Apr 2020 20:28:55 -0400 Subject: Remove unused libhardware dependency from libnativewindow libnativewindow only uses the android.hardware.graphics.common AIDL dependency. Bug: 155235859 Test: m -j Change-Id: I42b26c58ffcf0f19b78794e06449f60fb12d2ca6 --- libs/nativewindow/Android.bp | 1 - 1 file changed, 1 deletion(-) (limited to 'libs') diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index 55400c7b32..5baec2f70f 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -59,7 +59,6 @@ cc_library { ], shared_libs: [ - "libhardware", "libcutils", "liblog", "libutils", -- cgit v1.2.3-59-g8ed1b From 3ef1b76f9c6156774c65f754f8f9d1e236756bb7 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 30 Apr 2020 10:26:33 -0700 Subject: GLESRenderEngine: validate eglQueryStringImplementationANDROID for nullptr Log fatal the EGL error in case eglQueryStringImplementationANDROID returns nullptr; Bug: 155272618 Test: boot Change-Id: I4be7f798adfa7fdd7378dc509c847299f0539c7f --- libs/renderengine/gl/GLESRenderEngine.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index b0b4f6cb8b..92e7e715ea 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -208,9 +208,20 @@ std::unique_ptr GLESRenderEngine::create(const RenderEngineCre LOG_ALWAYS_FATAL("failed to initialize EGL"); } + const auto eglVersion = eglQueryStringImplementationANDROID(display, EGL_VERSION); + if (!eglVersion) { + checkGlError(__FUNCTION__, __LINE__); + LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_VERSION) failed"); + } + + const auto eglExtensions = eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS); + if (!eglExtensions) { + checkGlError(__FUNCTION__, __LINE__); + LOG_ALWAYS_FATAL("eglQueryStringImplementationANDROID(EGL_EXTENSIONS) failed"); + } + GLExtensions& extensions = GLExtensions::getInstance(); - extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION), - eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS)); + extensions.initWithEGLStrings(eglVersion, eglExtensions); // The code assumes that ES2 or later is available if this extension is // supported. -- cgit v1.2.3-59-g8ed1b From 19ce655ecf577d2ebb8e0936eb1a987f27ce46ac Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 30 Apr 2020 14:45:23 -0700 Subject: Apply display translation to blurred result Test: on notched device, hide cutout, swipe down the shade Fixes: 155130038 Change-Id: I216c77d2c6695c8faf8a0502f9d403a76403a2f6 --- libs/renderengine/gl/filters/BlurFilter.cpp | 6 ++++-- libs/renderengine/gl/filters/BlurFilter.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp index db55d17aec..19f18c0a7f 100644 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ b/libs/renderengine/gl/filters/BlurFilter.cpp @@ -68,6 +68,8 @@ BlurFilter::BlurFilter(GLESRenderEngine& engine) status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) { ATRACE_NAME("BlurFilter::setAsDrawTarget"); mRadius = radius; + mDisplayX = display.physicalDisplay.left; + mDisplayY = display.physicalDisplay.top; if (mDisplayWidth < display.physicalDisplay.width() || mDisplayHeight < display.physicalDisplay.height()) { @@ -182,8 +184,8 @@ status_t BlurFilter::render(bool multiPass) { if (mix >= 1 || multiPass) { mLastDrawTarget->bindAsReadBuffer(); glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(), - mLastDrawTarget->getBufferHeight(), 0, 0, mDisplayWidth, mDisplayHeight, - GL_COLOR_BUFFER_BIT, GL_LINEAR); + mLastDrawTarget->getBufferHeight(), mDisplayX, mDisplayY, mDisplayWidth, + mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); return NO_ERROR; } diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h index 9d3fc60e48..593a8fd54e 100644 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ b/libs/renderengine/gl/filters/BlurFilter.h @@ -68,6 +68,8 @@ private: GLFramebuffer mPongFbo; uint32_t mDisplayWidth = 0; uint32_t mDisplayHeight = 0; + uint32_t mDisplayX = 0; + uint32_t mDisplayY = 0; // Buffer holding the final blur pass. GLFramebuffer* mLastDrawTarget; -- cgit v1.2.3-59-g8ed1b From a9a6b46b9cbba23c161117f99ab15f46784d7ece Mon Sep 17 00:00:00 2001 From: Jagadeesh Pakaravoor Date: Fri, 1 May 2020 00:01:40 +0000 Subject: Revert^2 "libui: rewrite Region with FatVector" Revert submission 10449863-revert-fatvector Reason for revert: b/149254345 Original change (of introducing FatVector) was reverted as a stop-gap solution to fix the aforementioned bug. The bug was caused by an ABI lock between Surface's definition (that changed with Region) and lib-imsvt prebuilt. Enabling this change now as we have re-compiled the prebuilt with the change enabled. Doing that via a revert of the revert. Reverted Changes: I8ac66acb8:Revert "hwui: remove FatVector" Ib60dbf3ef:Revert "libui: rewrite Region with FatVector" Original changes: I09dc2fddd:hwui: remove FatVector I265c6c831:libui: rewrite Region with FatVector bug: 149254345 Change-Id: I723283a952e0908f595967af0037b0dc1351671b --- include/ui/FatVector.h | 1 + libs/ui/Region.cpp | 94 +++++++++++++++++++------------------ libs/ui/include/ui/FatVector.h | 93 ++++++++++++++++++++++++++++++++++++ libs/ui/include/ui/Region.h | 7 ++- libs/ui/include_vndk/ui/FatVector.h | 1 + 5 files changed, 146 insertions(+), 50 deletions(-) create mode 120000 include/ui/FatVector.h create mode 100644 libs/ui/include/ui/FatVector.h create mode 120000 libs/ui/include_vndk/ui/FatVector.h (limited to 'libs') diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h new file mode 120000 index 0000000000..c2047c07e1 --- /dev/null +++ b/include/ui/FatVector.h @@ -0,0 +1 @@ +../../libs/ui/include/ui/FatVector.h \ No newline at end of file diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index bf487c4aec..cd2a448c3e 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -67,19 +67,20 @@ const Region Region::INVALID_REGION(Rect::INVALID_RECT); // ---------------------------------------------------------------------------- Region::Region() { - mStorage.add(Rect(0,0)); + mStorage.push_back(Rect(0, 0)); } Region::Region(const Region& rhs) - : mStorage(rhs.mStorage) { + mStorage.clear(); + mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end()); #if defined(VALIDATE_REGIONS) validate(rhs, "rhs copy-ctor"); #endif } Region::Region(const Rect& rhs) { - mStorage.add(rhs); + mStorage.push_back(rhs); } Region::~Region() @@ -100,8 +101,8 @@ Region::~Region() * final, correctly ordered region buffer. Each rectangle will be compared with the span directly * above it, and subdivided to resolve any remaining T-junctions. */ -static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, - Vector& dst, int spanDirection) { +static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector& dst, + int spanDirection) { dst.clear(); const Rect* current = end - 1; @@ -109,7 +110,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, // add first span immediately do { - dst.add(*current); + dst.push_back(*current); current--; } while (current->top == lastTop && current >= begin); @@ -147,12 +148,12 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, if (prev.right <= left) break; if (prev.right > left && prev.right < right) { - dst.add(Rect(prev.right, top, right, bottom)); + dst.push_back(Rect(prev.right, top, right, bottom)); right = prev.right; } if (prev.left > left && prev.left < right) { - dst.add(Rect(prev.left, top, right, bottom)); + dst.push_back(Rect(prev.left, top, right, bottom)); right = prev.left; } @@ -166,12 +167,12 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, if (prev.left >= right) break; if (prev.left > left && prev.left < right) { - dst.add(Rect(left, top, prev.left, bottom)); + dst.push_back(Rect(left, top, prev.left, bottom)); left = prev.left; } if (prev.right > left && prev.right < right) { - dst.add(Rect(left, top, prev.right, bottom)); + dst.push_back(Rect(left, top, prev.right, bottom)); left = prev.right; } // if an entry in the previous span is too far left, nothing further right in the @@ -183,7 +184,7 @@ static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, } if (left < right) { - dst.add(Rect(left, top, right, bottom)); + dst.push_back(Rect(left, top, right, bottom)); } current--; @@ -201,13 +202,14 @@ Region Region::createTJunctionFreeRegion(const Region& r) { if (r.isEmpty()) return r; if (r.isRect()) return r; - Vector reversed; + FatVector reversed; reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL); Region outputRegion; - reverseRectsResolvingJunctions(reversed.begin(), reversed.end(), - outputRegion.mStorage, direction_LTR); - outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds + reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(), + outputRegion.mStorage, direction_LTR); + outputRegion.mStorage.push_back( + r.getBounds()); // to make region valid, mStorage must end with bounds #if defined(VALIDATE_REGIONS) validate(outputRegion, "T-Junction free region"); @@ -222,7 +224,8 @@ Region& Region::operator = (const Region& rhs) validate(*this, "this->operator="); validate(rhs, "rhs.operator="); #endif - mStorage = rhs.mStorage; + mStorage.clear(); + mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end()); return *this; } @@ -231,7 +234,7 @@ Region& Region::makeBoundsSelf() if (mStorage.size() >= 2) { const Rect bounds(getBounds()); mStorage.clear(); - mStorage.add(bounds); + mStorage.push_back(bounds); } return *this; } @@ -255,25 +258,25 @@ bool Region::contains(int x, int y) const { void Region::clear() { mStorage.clear(); - mStorage.add(Rect(0,0)); + mStorage.push_back(Rect(0, 0)); } void Region::set(const Rect& r) { mStorage.clear(); - mStorage.add(r); + mStorage.push_back(r); } void Region::set(int32_t w, int32_t h) { mStorage.clear(); - mStorage.add(Rect(w, h)); + mStorage.push_back(Rect(w, h)); } void Region::set(uint32_t w, uint32_t h) { mStorage.clear(); - mStorage.add(Rect(w, h)); + mStorage.push_back(Rect(w, h)); } bool Region::isTriviallyEqual(const Region& region) const { @@ -299,8 +302,7 @@ bool Region::hasSameRects(const Region& other) const { void Region::addRectUnchecked(int l, int t, int r, int b) { Rect rect(l,t,r,b); - size_t where = mStorage.size() - 1; - mStorage.insertAt(rect, where, 1); + mStorage.insert(mStorage.end() - 1, rect); } // ---------------------------------------------------------------------------- @@ -350,7 +352,7 @@ Region& Region::translateSelf(int x, int y) { Region& Region::scaleSelf(float sx, float sy) { size_t count = mStorage.size(); - Rect* rects = mStorage.editArray(); + Rect* rects = mStorage.data(); while (count) { rects->left = static_cast(static_cast(rects->left) * sx + 0.5f); rects->right = static_cast(static_cast(rects->right) * sx + 0.5f); @@ -455,10 +457,10 @@ const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) c class Region::rasterizer : public region_operator::region_rasterizer { Rect bounds; - Vector& storage; + FatVector& storage; Rect* head; Rect* tail; - Vector span; + FatVector span; Rect* cur; public: explicit rasterizer(Region& reg) @@ -485,8 +487,8 @@ Region::rasterizer::~rasterizer() flushSpan(); } if (storage.size()) { - bounds.top = storage.itemAt(0).top; - bounds.bottom = storage.top().bottom; + bounds.top = storage.front().top; + bounds.bottom = storage.back().bottom; if (storage.size() == 1) { storage.clear(); } @@ -494,7 +496,7 @@ Region::rasterizer::~rasterizer() bounds.left = 0; bounds.right = 0; } - storage.add(bounds); + storage.push_back(bounds); } void Region::rasterizer::operator()(const Rect& rect) @@ -509,15 +511,15 @@ void Region::rasterizer::operator()(const Rect& rect) return; } } - span.add(rect); - cur = span.editArray() + (span.size() - 1); + span.push_back(rect); + cur = span.data() + (span.size() - 1); } void Region::rasterizer::flushSpan() { bool merge = false; if (tail-head == ssize_t(span.size())) { - Rect const* p = span.editArray(); + Rect const* p = span.data(); Rect const* q = head; if (p->top == q->bottom) { merge = true; @@ -532,17 +534,17 @@ void Region::rasterizer::flushSpan() } } if (merge) { - const int bottom = span[0].bottom; + const int bottom = span.front().bottom; Rect* r = head; while (r != tail) { r->bottom = bottom; r++; } } else { - bounds.left = min(span.itemAt(0).left, bounds.left); - bounds.right = max(span.top().right, bounds.right); - storage.appendVector(span); - tail = storage.editArray() + storage.size(); + bounds.left = min(span.front().left, bounds.left); + bounds.right = max(span.back().right, bounds.right); + storage.insert(storage.end(), span.begin(), span.end()); + tail = storage.data() + storage.size(); head = tail - span.size(); } span.clear(); @@ -550,7 +552,7 @@ void Region::rasterizer::flushSpan() bool Region::validate(const Region& reg, const char* name, bool silent) { - if (reg.mStorage.isEmpty()) { + if (reg.mStorage.empty()) { ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name); // return immediately as the code below assumes mStorage is non-empty return false; @@ -689,9 +691,8 @@ void Region::boolean_operation(uint32_t op, Region& dst, } sk_dst.op(sk_lhs, sk_rhs, sk_op); - if (sk_dst.isEmpty() && dst.isEmpty()) - return; - + if (sk_dst.empty() && dst.empty()) return; + bool same = true; Region::const_iterator head = dst.begin(); Region::const_iterator const tail = dst.end(); @@ -786,7 +787,7 @@ void Region::translate(Region& reg, int dx, int dy) validate(reg, "translate (before)"); #endif size_t count = reg.mStorage.size(); - Rect* rects = reg.mStorage.editArray(); + Rect* rects = reg.mStorage.data(); while (count) { rects->offsetBy(dx, dy); rects++; @@ -866,24 +867,25 @@ status_t Region::unflatten(void const* buffer, size_t size) { ALOGE("Region::unflatten() failed, invalid region"); return BAD_VALUE; } - mStorage = result.mStorage; + mStorage.clear(); + mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end()); return NO_ERROR; } // ---------------------------------------------------------------------------- Region::const_iterator Region::begin() const { - return mStorage.array(); + return mStorage.data(); } Region::const_iterator Region::end() const { // Workaround for b/77643177 // mStorage should never be empty, but somehow it is and it's causing // an abort in ubsan - if (mStorage.isEmpty()) return mStorage.array(); + if (mStorage.empty()) return mStorage.data(); size_t numRects = isRect() ? 1 : mStorage.size() - 1; - return mStorage.array() + numRects; + return mStorage.data() + numRects; } Rect const* Region::getArray(size_t* count) const { diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h new file mode 100644 index 0000000000..25fe3a0a2a --- /dev/null +++ b/libs/ui/include/ui/FatVector.h @@ -0,0 +1,93 @@ +/* + * Copyright 2019, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_REGION_FAT_VECTOR_H +#define ANDROID_REGION_FAT_VECTOR_H + +#include +#include +#include +#include + +#include + +namespace android { + +template +class InlineStdAllocator { +public: + struct Allocation { + private: + Allocation(const Allocation&) = delete; + void operator=(const Allocation&) = delete; + + public: + Allocation() {} + // char array instead of T array, so memory is uninitialized, with no destructors run + char array[sizeof(T) * SIZE]; + bool inUse = false; + }; + + typedef T value_type; // needed to implement std::allocator + typedef T* pointer; // needed to implement std::allocator + + explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {} + InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {} + ~InlineStdAllocator() {} + + T* allocate(size_t num, const void* = 0) { + if (!mAllocation.inUse && num <= SIZE) { + mAllocation.inUse = true; + return static_cast(static_cast(mAllocation.array)); + } else { + return static_cast(static_cast(malloc(num * sizeof(T)))); + } + } + + void deallocate(pointer p, size_t) { + if (p == static_cast(static_cast(mAllocation.array))) { + mAllocation.inUse = false; + } else { + // 'free' instead of delete here - destruction handled separately + free(p); + } + } + Allocation& mAllocation; +}; + +/** + * std::vector with SIZE elements preallocated into an internal buffer. + * + * Useful for avoiding the cost of malloc in cases where only SIZE or + * fewer elements are needed in the common case. + */ +template +class FatVector : public std::vector> { +public: + FatVector() + : std::vector>(InlineStdAllocator(mAllocation)) { + this->reserve(SIZE); + } + + explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); } + +private: + typename InlineStdAllocator::Allocation mAllocation; +}; + +} // namespace android + +#endif // ANDROID_REGION_FAT_VECTOR_H diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h index 2db3b10f13..6bb7b8d21c 100644 --- a/libs/ui/include/ui/Region.h +++ b/libs/ui/include/ui/Region.h @@ -21,13 +21,13 @@ #include #include -#include - #include #include #include +#include "FatVector.h" + #include namespace android { @@ -180,7 +180,7 @@ private: // with an extra Rect as the last element which is set to the // bounds of the region. However, if the region is // a simple Rect then mStorage contains only that rect. - Vector mStorage; + FatVector mStorage; }; @@ -235,4 +235,3 @@ static inline void PrintTo(const Region& region, ::std::ostream* os) { }; // namespace android #endif // ANDROID_UI_REGION_H - diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h new file mode 120000 index 0000000000..bf30166784 --- /dev/null +++ b/libs/ui/include_vndk/ui/FatVector.h @@ -0,0 +1 @@ +../../include/ui/FatVector.h \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From f734df4201b74a7131ddd9558d7e6c9ea67a9b11 Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Mon, 13 Apr 2020 21:09:28 -0700 Subject: Split refresh rate range into two ranges To prevent low-priority refresh rate considerations from overriding the app frame rate as specified via the new setFrameRate() api, split the display refresh rate range into "primary" and "app request" ranges. The primary range includes the low priority considerations, while the app request range removes two lower priority considerations. In general, surface flinger will keep the display refresh rate within the primary range, but layers with frame rate settings via the setFrameRate() api may cause surface flinger to pick a refresh rate outside the primary range. Surface flinger will never choose a refresh rate outside the app request range specified by display manager. Bug: 148978562 Test: - Added a new unit test to DisplayModeDirectorTest to verify that display manager strips lower priority considerations when deciding the app request range. - Added a new unit test to RefreshRateConfigsTest to verify RefreshRateConfigs handles the primary vs app request range correctly. - Manual test: Confirmed that with the "force 90Hz refresh rate" option turned on, we don't switch to 60Hz when playing a 60Hz video. - Manual test: Confirmed that with the "force 90Hz refresh rate" option turned on, when an app calls setFrameRate(60), we stay at 60Hz. - Manual test: Modified a Pixel 4 XL to prefer 60Hz in low brightness, entered low brightness, and confirmed we don't touch boost to 90Hz. - Manual test: Confirmed that Maps stays at 60Hz on Pixel 4. - Manual test: Turned on verbose logs in RefreshRateConfigs.cpp, confirmed they look good. - Manual test: Inspected dumpsys output, confirmed the primary and app request refresh rate ranges are printed correctly. Change-Id: Ib16cc9b6158efa575cdbfbb7a0ad014008a3e5af --- libs/gui/ISurfaceComposer.cpp | 129 +++++++++++++++----- libs/gui/SurfaceComposerClient.cpp | 28 +++-- libs/gui/include/gui/ISurfaceComposer.h | 33 +++-- libs/gui/include/gui/SurfaceComposerClient.h | 22 ++-- libs/gui/tests/Surface_test.cpp | 13 +- .../Scheduler/RefreshRateConfigs.cpp | 135 ++++++++++++++------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 62 ++++++++-- services/surfaceflinger/Scheduler/Scheduler.cpp | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 54 ++++++--- services/surfaceflinger/SurfaceFlinger.h | 11 +- services/surfaceflinger/tests/Credentials_test.cpp | 19 ++- .../surfaceflinger/tests/DisplayConfigs_test.cpp | 34 ++++-- .../tests/fakehwc/SFFakeHwc_test.cpp | 16 ++- .../tests/unittests/RefreshRateConfigsTest.cpp | 91 +++++++++++--- 14 files changed, 469 insertions(+), 184 deletions(-) (limited to 'libs') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 6fd53cf47a..2a27a9a278 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -931,8 +931,11 @@ public: } virtual status_t setDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t defaultConfig, float minRefreshRate, - float maxRefreshRate) { + int32_t defaultConfig, + float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -949,14 +952,26 @@ public: ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result); return result; } - result = data.writeFloat(minRefreshRate); + result = data.writeFloat(primaryRefreshRateMin); if (result != NO_ERROR) { - ALOGE("setDesiredDisplayConfigSpecs failed to write minRefreshRate: %d", result); + ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result); return result; } - result = data.writeFloat(maxRefreshRate); + result = data.writeFloat(primaryRefreshRateMax); if (result != NO_ERROR) { - ALOGE("setDesiredDisplayConfigSpecs failed to write maxRefreshRate: %d", result); + ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMax: %d", result); + return result; + } + result = data.writeFloat(appRequestRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d", + result); + return result; + } + result = data.writeFloat(appRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMax: %d", + result); return result; } @@ -971,9 +986,14 @@ public: virtual status_t getDesiredDisplayConfigSpecs(const sp& displayToken, int32_t* outDefaultConfig, - float* outMinRefreshRate, - float* outMaxRefreshRate) { - if (!outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) return BAD_VALUE; + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { + if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax || + !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { + return BAD_VALUE; + } Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -996,14 +1016,26 @@ public: ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result); return result; } - result = reply.readFloat(outMinRefreshRate); + result = reply.readFloat(outPrimaryRefreshRateMin); if (result != NO_ERROR) { - ALOGE("getDesiredDisplayConfigSpecs failed to read minRefreshRate: %d", result); + ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result); return result; } - result = reply.readFloat(outMaxRefreshRate); + result = reply.readFloat(outPrimaryRefreshRateMax); if (result != NO_ERROR) { - ALOGE("getDesiredDisplayConfigSpecs failed to read maxRefreshRate: %d", result); + ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result); + return result; + } + result = reply.readFloat(outAppRequestRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d", + result); + return result; + } + result = reply.readFloat(outAppRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d", + result); return result; } return reply.readInt32(); @@ -1835,20 +1867,38 @@ status_t BnSurfaceComposer::onTransact( ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result); return result; } - float minRefreshRate; - result = data.readFloat(&minRefreshRate); + float primaryRefreshRateMin; + result = data.readFloat(&primaryRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMin: %d", + result); + return result; + } + float primaryRefreshRateMax; + result = data.readFloat(&primaryRefreshRateMax); if (result != NO_ERROR) { - ALOGE("setDesiredDisplayConfigSpecs: failed to read minRefreshRate: %d", result); + ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMax: %d", + result); return result; } - float maxRefreshRate; - result = data.readFloat(&maxRefreshRate); + float appRequestRefreshRateMin; + result = data.readFloat(&appRequestRefreshRateMin); if (result != NO_ERROR) { - ALOGE("setDesiredDisplayConfigSpecs: failed to read maxRefreshRate: %d", result); + ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMin: %d", + result); return result; } - result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, minRefreshRate, - maxRefreshRate); + float appRequestRefreshRateMax; + result = data.readFloat(&appRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMax: %d", + result); + return result; + } + result = + setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin, + primaryRefreshRateMax, appRequestRefreshRateMin, + appRequestRefreshRateMax); if (result != NO_ERROR) { ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: " "%d", @@ -1862,11 +1912,16 @@ status_t BnSurfaceComposer::onTransact( CHECK_INTERFACE(ISurfaceComposer, data, reply); sp displayToken = data.readStrongBinder(); int32_t defaultConfig; - float minRefreshRate; - float maxRefreshRate; - - status_t result = getDesiredDisplayConfigSpecs(displayToken, &defaultConfig, - &minRefreshRate, &maxRefreshRate); + float primaryRefreshRateMin; + float primaryRefreshRateMax; + float appRequestRefreshRateMin; + float appRequestRefreshRateMax; + + status_t result = + getDesiredDisplayConfigSpecs(displayToken, &defaultConfig, + &primaryRefreshRateMin, &primaryRefreshRateMax, + &appRequestRefreshRateMin, + &appRequestRefreshRateMax); if (result != NO_ERROR) { ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: " "%d", @@ -1879,14 +1934,28 @@ status_t BnSurfaceComposer::onTransact( ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result); return result; } - result = reply->writeFloat(minRefreshRate); + result = reply->writeFloat(primaryRefreshRateMin); if (result != NO_ERROR) { - ALOGE("getDesiredDisplayConfigSpecs: failed to write minRefreshRate: %d", result); + ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d", + result); return result; } - result = reply->writeFloat(maxRefreshRate); + result = reply->writeFloat(primaryRefreshRateMax); if (result != NO_ERROR) { - ALOGE("getDesiredDisplayConfigSpecs: failed to write maxRefreshRate: %d", result); + ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d", + result); + return result; + } + result = reply->writeFloat(appRequestRefreshRateMin); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d", + result); + return result; + } + result = reply->writeFloat(appRequestRefreshRateMax); + if (result != NO_ERROR) { + ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d", + result); return result; } reply->writeInt32(result); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d9cbeb71d2..a52f298e77 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1698,22 +1698,26 @@ int SurfaceComposerClient::getActiveConfig(const sp& display) { status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp& displayToken, int32_t defaultConfig, - float minRefreshRate, - float maxRefreshRate) { - return ComposerService::getComposerService()->setDesiredDisplayConfigSpecs(displayToken, - defaultConfig, - minRefreshRate, - maxRefreshRate); + float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { + return ComposerService::getComposerService() + ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin, + primaryRefreshRateMax, appRequestRefreshRateMin, + appRequestRefreshRateMax); } status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp& displayToken, int32_t* outDefaultConfig, - float* outMinRefreshRate, - float* outMaxRefreshRate) { - return ComposerService::getComposerService()->getDesiredDisplayConfigSpecs(displayToken, - outDefaultConfig, - outMinRefreshRate, - outMaxRefreshRate); + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { + return ComposerService::getComposerService() + ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin, + outPrimaryRefreshRateMax, outAppRequestRefreshRateMin, + outAppRequestRefreshRateMax); } status_t SurfaceComposerClient::getDisplayColorModes(const sp& display, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b4a3fbec2a..0d33b3f695 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -426,19 +426,36 @@ public: */ virtual status_t removeRegionSamplingListener(const sp& listener) = 0; - /* - * Sets the refresh rate boundaries for display configuration. - * For all other parameters, default configuration is used. The index for the default is - * corresponding to the configs returned from getDisplayConfigs(). + /* Sets the refresh rate boundaries for the display. + * + * The primary refresh rate range represents display manager's general guidance on the display + * configs we'll consider when switching refresh rates. Unless we get an explicit signal from an + * app, we should stay within this range. + * + * The app request refresh rate range allows us to consider more display configs when switching + * refresh rates. Although we should generally stay within the primary range, specific + * considerations, such as layer frame rate settings specified via the setFrameRate() api, may + * cause us to go outside the primary range. We never go outside the app request range. The app + * request range will be greater than or equal to the primary refresh rate range, never smaller. + * + * defaultConfig is used to narrow the list of display configs SurfaceFlinger will consider + * switching between. Only configs with a config group and resolution matching defaultConfig + * will be considered for switching. The defaultConfig index corresponds to the list of configs + * returned from getDisplayConfigs(). */ virtual status_t setDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t defaultConfig, float minRefreshRate, - float maxRefreshRate) = 0; + int32_t defaultConfig, + float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) = 0; virtual status_t getDesiredDisplayConfigSpecs(const sp& displayToken, int32_t* outDefaultConfig, - float* outMinRefreshRate, - float* outMaxRefreshRate) = 0; + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) = 0; /* * Gets whether brightness operations are supported on a display. * diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2fb9538390..531aed7ac4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -118,21 +118,19 @@ public: // Shorthand for getDisplayConfigs element at getActiveConfig index. static status_t getActiveDisplayConfig(const sp& display, DisplayConfig*); - // Sets the refresh rate boundaries for display configuration. - // For all other parameters, default configuration is used. The index for the default is - // corresponting to the configs returned from getDisplayConfigs(). + // Sets the refresh rate boundaries for the display. static status_t setDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t defaultConfig, float minRefreshRate, - float maxRefreshRate); - // Gets the refresh rate boundaries for display configuration. - // For all other parameters, default configuration is used. The index for the default is - // corresponting to the configs returned from getDisplayConfigs(). - // The reason is passed in for telemetry tracking, and it corresponds to the list of all - // the policy rules that were used. + int32_t defaultConfig, float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax); + // Gets the refresh rate boundaries for the display. static status_t getDesiredDisplayConfigSpecs(const sp& displayToken, int32_t* outDefaultConfig, - float* outMinRefreshRate, - float* outMaxRefreshRate); + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax); // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp& display, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d1d770e542..6374d747c7 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -835,14 +835,19 @@ public: return NO_ERROR; } status_t setDesiredDisplayConfigSpecs(const sp& /*displayToken*/, - int32_t /*defaultConfig*/, float /*minRefreshRate*/, - float /*maxRefreshRate*/) { + int32_t /*defaultConfig*/, + float /*primaryRefreshRateMin*/, + float /*primaryRefreshRateMax*/, + float /*appRequestRefreshRateMin*/, + float /*appRequestRefreshRateMax*/) { return NO_ERROR; } status_t getDesiredDisplayConfigSpecs(const sp& /*displayToken*/, int32_t* /*outDefaultConfig*/, - float* /*outMinRefreshRate*/, - float* /*outMaxRefreshRate*/) override { + float* /*outPrimaryRefreshRateMin*/, + float* /*outPrimaryRefreshRateMax*/, + float* /*outAppRequestRefreshRateMin*/, + float* /*outAppRequestRefreshRateMax*/) override { return NO_ERROR; }; status_t notifyPowerHint(int32_t /*hintId*/) override { return NO_ERROR; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 5634adb9fd..43e67c2bd1 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -58,7 +58,7 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContent( ATRACE_INT("ContentFPS", contentFramerate); // Find the appropriate refresh rate with minimal error - auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(), + auto iter = min_element(mPrimaryRefreshRates.cbegin(), mPrimaryRefreshRates.cend(), [contentFramerate](const auto& lhs, const auto& rhs) -> bool { return std::abs(lhs->fps - contentFramerate) < std::abs(rhs->fps - contentFramerate); @@ -71,7 +71,7 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContent( constexpr float MARGIN = 0.05f; float ratio = (*iter)->fps / contentFramerate; if (std::abs(std::round(ratio) - ratio) > MARGIN) { - while (iter != mAvailableRefreshRates.cend()) { + while (iter != mPrimaryRefreshRates.cend()) { ratio = (*iter)->fps / contentFramerate; if (std::abs(std::round(ratio) - ratio) <= MARGIN) { @@ -110,7 +110,8 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( // refresh rate. if (layers.empty()) { *touchConsidered = touchActive; - return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked(); + return touchActive ? getMaxRefreshRateByPolicyLocked() + : getCurrentRefreshRateByPolicyLocked(); } int noVoteLayers = 0; @@ -135,25 +136,25 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( } } - // Consider the touch event if there are no ExplicitDefault layers. - // ExplicitDefault are mostly interactive (as opposed to ExplicitExactOrMultiple) - // and therefore if those posted an explicit vote we should not change it - // if get get a touch event. - if (touchActive && explicitDefaultVoteLayers == 0) { + // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've + // selected a refresh rate to see if we should apply touch boost. + if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) { *touchConsidered = true; - return *mAvailableRefreshRates.back(); + return getMaxRefreshRateByPolicyLocked(); } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { - return *mAvailableRefreshRates.front(); + return getMinRefreshRateByPolicyLocked(); } + const Policy* policy = getCurrentPolicyLocked(); + // Find the best refresh rate based on score std::vector> scores; - scores.reserve(mAvailableRefreshRates.size()); + scores.reserve(mAppRequestRefreshRates.size()); - for (const auto refreshRate : mAvailableRefreshRates) { + for (const auto refreshRate : mAppRequestRefreshRates) { scores.emplace_back(refreshRate, 0.0f); } @@ -166,6 +167,15 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( auto weight = layer.weight; for (auto i = 0u; i < scores.size(); i++) { + bool inPrimaryRange = + scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max); + if (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault && + layer.vote != LayerVoteType::ExplicitExactOrMultiple) { + // Only layers with explicit frame rate settings are allowed to score refresh rates + // outside the primary range. + continue; + } + // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto ratio = scores[i].first->fps / scores.back().first->fps; @@ -249,6 +259,17 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( ? getBestRefreshRate(scores.rbegin(), scores.rend()) : getBestRefreshRate(scores.begin(), scores.end()); + // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly + // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit + // vote we should not change it if we get a touch event. Only apply touch boost if it will + // actually increase the refresh rate over the normal selection. + const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(); + if (touchActive && explicitDefaultVoteLayers == 0 && + bestRefreshRate->fps < touchRefreshRate.fps) { + *touchConsidered = true; + return touchRefreshRate; + } + return *bestRefreshRate; } @@ -278,12 +299,20 @@ const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const { const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const { std::lock_guard lock(mLock); - return *mAvailableRefreshRates.front(); + return getMinRefreshRateByPolicyLocked(); +} + +const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { + return *mPrimaryRefreshRates.front(); } const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const { std::lock_guard lock(mLock); - return *mAvailableRefreshRates.back(); + return getMaxRefreshRateByPolicyLocked(); +} + +const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { + return *mPrimaryRefreshRates.back(); } const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const { @@ -297,8 +326,8 @@ const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicy() const { } const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const { - if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(), - mCurrentRefreshRate) != mAvailableRefreshRates.end()) { + if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(), + mCurrentRefreshRate) != mAppRequestRefreshRates.end()) { return *mCurrentRefreshRate; } return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig); @@ -320,7 +349,7 @@ RefreshRateConfigs::RefreshRateConfigs( const float fps = 1e9f / config->getVsyncPeriod(); mRefreshRates.emplace(configId, std::make_unique(configId, config, - base::StringPrintf("%2.ffps", fps), fps, + base::StringPrintf("%.0ffps", fps), fps, RefreshRate::ConstructorTag(0))); if (configId == currentConfigId) { mCurrentRefreshRate = mRefreshRates.at(configId).get(); @@ -342,10 +371,11 @@ bool RefreshRateConfigs::isPolicyValid(const Policy& policy) { return false; } const RefreshRate& refreshRate = *iter->second; - if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) { + if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) { return false; } - return true; + return policy.appRequestRange.min <= policy.primaryRange.min && + policy.appRequestRange.max >= policy.primaryRange.max; } status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) { @@ -392,7 +422,7 @@ RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const { bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const { std::lock_guard lock(mLock); - for (const RefreshRate* refreshRate : mAvailableRefreshRates) { + for (const RefreshRate* refreshRate : mAppRequestRefreshRates) { if (refreshRate->configId == config) { return true; } @@ -430,33 +460,44 @@ void RefreshRateConfigs::constructAvailableRefreshRates() { // Filter configs based on current policy and sort based on vsync period const Policy* policy = getCurrentPolicyLocked(); const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig; - ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f", - policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->minRefreshRate, - policy->maxRefreshRate); - getSortedRefreshRateList( - [&](const RefreshRate& refreshRate) REQUIRES(mLock) { - const auto& hwcConfig = refreshRate.hwcConfig; - - return hwcConfig->getHeight() == defaultConfig->getHeight() && - hwcConfig->getWidth() == defaultConfig->getWidth() && - hwcConfig->getDpiX() == defaultConfig->getDpiX() && - hwcConfig->getDpiY() == defaultConfig->getDpiY() && - (policy->allowGroupSwitching || - hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) && - refreshRate.inPolicy(policy->minRefreshRate, policy->maxRefreshRate); - }, - &mAvailableRefreshRates); - - std::string availableRefreshRates; - for (const auto& refreshRate : mAvailableRefreshRates) { - base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str()); - } - - ALOGV("Available refresh rates: %s", availableRefreshRates.c_str()); - LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(), - "No compatible display configs for default=%d min=%.0f max=%.0f", - policy->defaultConfig.value(), policy->minRefreshRate, - policy->maxRefreshRate); + ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]" + " appRequestRange=[%.2f %.2f]", + policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min, + policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max); + + auto filterRefreshRates = [&](float min, float max, const char* listName, + std::vector* outRefreshRates) { + getSortedRefreshRateList( + [&](const RefreshRate& refreshRate) REQUIRES(mLock) { + const auto& hwcConfig = refreshRate.hwcConfig; + + return hwcConfig->getHeight() == defaultConfig->getHeight() && + hwcConfig->getWidth() == defaultConfig->getWidth() && + hwcConfig->getDpiX() == defaultConfig->getDpiX() && + hwcConfig->getDpiY() == defaultConfig->getDpiY() && + (policy->allowGroupSwitching || + hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) && + refreshRate.inPolicy(min, max); + }, + outRefreshRates); + + LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(), + "No matching configs for %s range: min=%.0f max=%.0f", listName, min, + max); + auto stringifyRefreshRates = [&]() -> std::string { + std::string str; + for (auto refreshRate : *outRefreshRates) { + base::StringAppendF(&str, "%s ", refreshRate->name.c_str()); + } + return str; + }; + ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str()); + }; + + filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary", + &mPrimaryRefreshRates); + filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request", + &mAppRequestRefreshRates); } } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index dea7e90896..e8a7bef771 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -107,18 +107,46 @@ public: std::unordered_map>; struct Policy { + struct Range { + float min = 0; + float max = std::numeric_limits::max(); + + bool operator==(const Range& other) const { + return min == other.min && max == other.max; + } + + bool operator!=(const Range& other) const { return !(*this == other); } + }; + // The default config, used to ensure we only initiate display config switches within the // same config group as defaultConfigId's group. HwcConfigIndexType defaultConfig; - // The min and max FPS allowed by the policy. - float minRefreshRate = 0; - float maxRefreshRate = std::numeric_limits::max(); + // The primary refresh rate range represents display manager's general guidance on the + // display configs we'll consider when switching refresh rates. Unless we get an explicit + // signal from an app, we should stay within this range. + Range primaryRange; + // The app request refresh rate range allows us to consider more display configs when + // switching refresh rates. Although we should generally stay within the primary range, + // specific considerations, such as layer frame rate settings specified via the + // setFrameRate() api, may cause us to go outside the primary range. We never go outside the + // app request range. The app request range will be greater than or equal to the primary + // refresh rate range, never smaller. + Range appRequestRange; // Whether or not we switch config groups to get the best frame rate. Only used by tests. bool allowGroupSwitching = false; + Policy() = default; + Policy(HwcConfigIndexType defaultConfig, const Range& range) + : Policy(defaultConfig, range, range) {} + Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange, + const Range& appRequestRange) + : defaultConfig(defaultConfig), + primaryRange(primaryRange), + appRequestRange(appRequestRange) {} + bool operator==(const Policy& other) const { - return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate && - maxRefreshRate == other.maxRefreshRate && + return defaultConfig == other.defaultConfig && primaryRange == other.primaryRange && + appRequestRange == other.appRequestRange && allowGroupSwitching == other.allowGroupSwitching; } @@ -198,13 +226,15 @@ public: // Returns the lowest refresh rate supported by the device. This won't change at runtime. const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; } - // Returns the lowest refresh rate according to the current policy. May change in runtime. + // Returns the lowest refresh rate according to the current policy. May change at runtime. Only + // uses the primary range, not the app request range. const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock); // Returns the highest refresh rate supported by the device. This won't change at runtime. const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; } - // Returns the highest refresh rate according to the current policy. May change in runtime. + // Returns the highest refresh rate according to the current policy. May change at runtime. Only + // uses the primary range, not the app request range. const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock); // Returns the current refresh rate @@ -243,6 +273,14 @@ private: // display refresh period. std::pair getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const; + // Returns the lowest refresh rate according to the current policy. May change at runtime. Only + // uses the primary range, not the app request range. + const RefreshRate& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock); + + // Returns the highest refresh rate according to the current policy. May change at runtime. Only + // uses the primary range, not the app request range. + const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock); + // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by // the policy. const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock); @@ -254,9 +292,13 @@ private: // object is initialized. AllRefreshRatesMapType mRefreshRates; - // The list of refresh rates which are available in the current policy, ordered by vsyncPeriod - // (the first element is the lowest refresh rate) - std::vector mAvailableRefreshRates GUARDED_BY(mLock); + // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod + // (the first element is the lowest refresh rate). + std::vector mPrimaryRefreshRates GUARDED_BY(mLock); + + // The list of refresh rates in the app request range of the current policy, ordered by + // vsyncPeriod (the first element is the lowest refresh rate). + std::vector mAppRequestRefreshRates GUARDED_BY(mLock); // The current config. This will change at runtime. This is set by SurfaceFlinger on // the main thread, and read by the Scheduler (and other objects) on other threads. diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 86bb6eb7de..217c777f8c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -574,10 +574,8 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { ATRACE_CALL(); - // NOTE: If we remove the kernel idle timer, and use our internal idle timer, this - // code will have to be refactored. If Display Power is not in normal operation we want to be in - // performance mode. When coming back to normal mode, a grace period is given with - // DisplayPowerTimer. + // If Display Power is not in normal operation we want to be in performance mode. When coming + // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset)) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 29434990f6..c05d61c3b9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1002,7 +1002,7 @@ status_t SurfaceFlinger::setActiveConfig(const sp& displayToken, int mo } else { const HwcConfigIndexType config(mode); const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps(); - const scheduler::RefreshRateConfigs::Policy policy{config, fps, fps}; + const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}}; constexpr bool kOverridePolicy = false; return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy); @@ -4371,17 +4371,19 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d" - ", min: %.2f Hz, max: %.2f Hz", - policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate); + ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n", + policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max, + policy.appRequestRange.min, policy.appRequestRange.max); StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); if (currentPolicy != policy) { StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): default config ID: %d" - ", min: %.2f Hz, max: %.2f Hz\n\n", - currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate, - currentPolicy.maxRefreshRate); + ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n", + currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min, + currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min, + currentPolicy.appRequestRange.max); } mScheduler->dump(mAppConnectionHandle, result); @@ -5916,9 +5918,11 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( } scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy(); - ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f", - currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate, - currentPolicy.maxRefreshRate); + ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]" + " expandedRange: [%.0f %.0f]", + currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min, + currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min, + currentPolicy.appRequestRange.max); // TODO(b/140204874): This hack triggers a notification that something has changed, so // that listeners that care about a change in allowed configs can get the notification. @@ -5951,8 +5955,11 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal( } status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t defaultConfig, float minRefreshRate, - float maxRefreshRate) { + int32_t defaultConfig, + float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { ATRACE_CALL(); if (!displayToken) { @@ -5970,7 +5977,9 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp& display return INVALID_OPERATION; } else { using Policy = scheduler::RefreshRateConfigs::Policy; - const Policy policy{HwcConfigIndexType(defaultConfig), minRefreshRate, maxRefreshRate}; + const Policy policy{HwcConfigIndexType(defaultConfig), + {primaryRefreshRateMin, primaryRefreshRateMax}, + {appRequestRefreshRateMin, appRequestRefreshRateMax}}; constexpr bool kOverridePolicy = false; return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy); @@ -5982,11 +5991,14 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp& display status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp& displayToken, int32_t* outDefaultConfig, - float* outMinRefreshRate, - float* outMaxRefreshRate) { + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { ATRACE_CALL(); - if (!displayToken || !outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) { + if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin || + !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { return BAD_VALUE; } @@ -6000,8 +6012,10 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp& display scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); *outDefaultConfig = policy.defaultConfig.value(); - *outMinRefreshRate = policy.minRefreshRate; - *outMaxRefreshRate = policy.maxRefreshRate; + *outPrimaryRefreshRateMin = policy.primaryRange.min; + *outPrimaryRefreshRateMax = policy.primaryRange.max; + *outAppRequestRefreshRateMin = policy.appRequestRange.min; + *outAppRequestRefreshRateMax = policy.appRequestRange.max; return NO_ERROR; } else if (display->isVirtual()) { return INVALID_OPERATION; @@ -6011,8 +6025,10 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp& display *outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId); auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod(); - *outMinRefreshRate = 1e9f / vsyncPeriod; - *outMaxRefreshRate = 1e9f / vsyncPeriod; + *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod; + *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod; + *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod; + *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod; return NO_ERROR; } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b65e4f6899..9f14fba0af 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -493,10 +493,15 @@ private: const sp& listener) override; status_t removeRegionSamplingListener(const sp& listener) override; status_t setDesiredDisplayConfigSpecs(const sp& displayToken, int32_t displayModeId, - float minRefreshRate, float maxRefreshRate) override; + float primaryRefreshRateMin, float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) override; status_t getDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t* outDefaultConfig, float* outMinRefreshRate, - float* outMaxRefreshRate) override; + int32_t* outDefaultConfig, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) override; status_t getDisplayBrightnessSupport(const sp& displayToken, bool* outSupport) const override; status_t setDisplayBrightness(const sp& displayToken, float brightness) override; diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 507d28b143..c136708ff0 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -215,14 +215,21 @@ TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) { TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); int32_t defaultConfig; - float minFps; - float maxFps; - status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig, - &minFps, &maxFps); + float primaryFpsMin; + float primaryFpsMax; + float appRequestFpsMin; + float appRequestFpsMax; + status_t res = + SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig, + &primaryFpsMin, &primaryFpsMax, + &appRequestFpsMin, + &appRequestFpsMax); ASSERT_EQ(res, NO_ERROR); std::function condition = [=]() { - return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, minFps, - maxFps); + return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, + primaryFpsMin, primaryFpsMax, + appRequestFpsMin, + appRequestFpsMax); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp index 0ed2ffb505..debfe83577 100644 --- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp +++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp @@ -39,11 +39,16 @@ protected: TEST_F(RefreshRateRangeTest, setAllConfigs) { int32_t initialDefaultConfig; - float initialMin; - float initialMax; + float initialPrimaryMin; + float initialPrimaryMax; + float initialAppRequestMin; + float initialAppRequestMax; status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &initialDefaultConfig, - &initialMin, &initialMax); + &initialPrimaryMin, + &initialPrimaryMax, + &initialAppRequestMin, + &initialAppRequestMax); ASSERT_EQ(res, NO_ERROR); Vector configs; @@ -52,23 +57,34 @@ TEST_F(RefreshRateRangeTest, setAllConfigs) { for (size_t i = 0; i < configs.size(); i++) { res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i, + configs[i].refreshRate, + configs[i].refreshRate, configs[i].refreshRate, configs[i].refreshRate); ASSERT_EQ(res, NO_ERROR); int defaultConfig; - float minRefreshRate; - float maxRefreshRate; + float primaryRefreshRateMin; + float primaryRefreshRateMax; + float appRequestRefreshRateMin; + float appRequestRefreshRateMax; res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig, - &minRefreshRate, &maxRefreshRate); + &primaryRefreshRateMin, + &primaryRefreshRateMax, + &appRequestRefreshRateMin, + &appRequestRefreshRateMax); ASSERT_EQ(res, NO_ERROR); ASSERT_EQ(defaultConfig, i); - ASSERT_EQ(minRefreshRate, configs[i].refreshRate); - ASSERT_EQ(maxRefreshRate, configs[i].refreshRate); + ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate); + ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate); + ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate); + ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate); } res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig, - initialMin, initialMax); + initialPrimaryMin, initialPrimaryMax, + initialAppRequestMin, + initialAppRequestMax); ASSERT_EQ(res, NO_ERROR); } diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 32c58ad390..a03fd89297 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -442,6 +442,8 @@ protected: if (config.resolution.getWidth() == 800) { EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, + config.refreshRate, + config.refreshRate, config.refreshRate, config.refreshRate)); waitForDisplayTransaction(); @@ -546,6 +548,8 @@ protected: if (config.refreshRate == 1e9f / 11'111'111) { EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, + config.refreshRate, + config.refreshRate, config.refreshRate, config.refreshRate)); waitForDisplayTransaction(); @@ -659,9 +663,11 @@ protected: const auto& config = configs[i]; if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) { EXPECT_EQ(NO_ERROR, - SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, - configs[i].refreshRate, - configs[i].refreshRate)); + SurfaceComposerClient:: + setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate, + configs[i].refreshRate, + configs[i].refreshRate, + configs[i].refreshRate)); waitForDisplayTransaction(); EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i)); break; @@ -705,6 +711,8 @@ protected: if (config.refreshRate == 1e9f / 8'333'333) { EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, + config.refreshRate, + config.refreshRate, config.refreshRate, config.refreshRate)); waitForDisplayTransaction(); @@ -750,6 +758,8 @@ protected: if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) { EXPECT_EQ(NO_ERROR, SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, + config.refreshRate, + config.refreshRate, config.refreshRate, config.refreshRate)); waitForDisplayTransaction(); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 2ceb89c3e3..47addc8bd9 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -166,8 +166,8 @@ TEST_F(RefreshRateConfigsTest, invalidPolicy) { auto refreshRateConfigs = std::make_unique(m60OnlyConfigDevice, /*currentConfigId=*/HWC_CONFIG_ID_60); - ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0); - ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0); + ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { @@ -201,7 +201,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe ASSERT_EQ(mExpected60Config, minRate60); ASSERT_EQ(mExpected60Config, performanceRate60); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0); refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); @@ -226,7 +226,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe ASSERT_EQ(mExpected60Config, minRate60); ASSERT_EQ(mExpected60Config, performanceRate60); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0); refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); @@ -248,7 +248,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { ASSERT_EQ(mExpected60Config, minRate); ASSERT_EQ(mExpected90Config, performanceRate); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0); auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); @@ -271,7 +271,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90); } - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0); { auto& current = refreshRateConfigs->getCurrentRefreshRate(); EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90); @@ -298,7 +298,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0); EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(mExpected60Config, @@ -310,7 +310,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0); EXPECT_EQ(mExpected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(mExpected90Config, @@ -321,7 +321,7 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f))); EXPECT_EQ(mExpected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f))); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0); EXPECT_EQ(mExpected90Config, refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f))); EXPECT_EQ(mExpected60Config, @@ -407,7 +407,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { &ignored)); lr.name = ""; - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(mExpected60Config, @@ -445,7 +445,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, &ignored)); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(mExpected90Config, @@ -483,7 +483,7 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) { refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, &ignored)); - ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0); + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0); lr.vote = LayerVoteType::Min; EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false, @@ -1130,7 +1130,8 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr1.desiredRefreshRate = 60.0f; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.name = "NoVote"; + lr2.desiredRefreshRate = 60.0f; + lr2.name = "60Hz Heuristic"; refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); EXPECT_EQ(true, touchConsidered); @@ -1138,7 +1139,8 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr1.desiredRefreshRate = 60.0f; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.name = "NoVote"; + lr2.desiredRefreshRate = 60.0f; + lr2.name = "60Hz Heuristic"; refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); EXPECT_EQ(false, touchConsidered); @@ -1146,15 +1148,17 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) { lr1.desiredRefreshRate = 60.0f; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.name = "NoVote"; + lr2.desiredRefreshRate = 60.0f; + lr2.name = "60Hz Heuristic"; refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); EXPECT_EQ(true, touchConsidered); lr1.vote = LayerVoteType::ExplicitDefault; lr1.desiredRefreshRate = 60.0f; - lr1.name = "60Hz ExplicitExactrMultiple"; + lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Heuristic; - lr2.name = "NoVote"; + lr2.desiredRefreshRate = 60.0f; + lr2.name = "60Hz Heuristic"; refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered); EXPECT_EQ(false, touchConsidered); } @@ -1227,6 +1231,59 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) { .getConfigId()); } +TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { + auto refreshRateConfigs = + std::make_unique(m60_90Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + layers[0].name = "Test layer"; + + // Return the config ID from calling getRefreshRateForContentV2() for a single layer with the + // given voteType and fps. + auto getFrameRate = [&](LayerVoteType voteType, float fps, + bool touchActive = false) -> HwcConfigIndexType { + layers[0].vote = voteType; + layers[0].desiredRefreshRate = fps; + bool touchConsidered; + return refreshRateConfigs->getRefreshRateForContentV2(layers, touchActive, &touchConsidered) + .getConfigId(); + }; + + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( + {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}), + 0); + bool touchConsidered; + EXPECT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs + ->getRefreshRateForContentV2({}, /*touchActive=*/false, &touchConsidered) + .getConfigId()); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f)); + + // Touch boost should be restricted to the primary range. + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true)); + // When we're higher than the primary range max due to a layer frame rate setting, touch boost + // shouldn't drag us back down to the primary range max. + EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true)); + EXPECT_EQ(HWC_CONFIG_ID_90, + getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true)); + + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy( + {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}), + 0); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f)); + EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f)); +} + } // namespace } // namespace scheduler } // namespace android -- cgit v1.2.3-59-g8ed1b From 53e19a76a441fbc85a094c046ac6a33f2dc5d386 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Fri, 1 May 2020 17:19:57 -0400 Subject: Update libgui to use android::base properties instead of cutils Clean up cutils/properties.h headers as some files were including it and not using it. Also update DebugEGLImageTracker to use android::base properties because it works on host and is generally more concise. Bug: 155436554 Test: build, flash and boot Change-Id: I1dc7060cae9811b69aac9bb36b71b69cd6ecba93 --- libs/gui/BLASTBufferQueue.cpp | 2 -- libs/gui/BufferQueueCore.cpp | 1 - libs/gui/DebugEGLImageTracker.cpp | 8 +++----- libs/gui/tests/Surface_test.cpp | 1 - 4 files changed, 3 insertions(+), 9 deletions(-) (limited to 'libs') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 5965201341..56591bdc63 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -19,8 +19,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include - #include #include #include diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index a1803d8f0e..8d80833ebe 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -28,7 +28,6 @@ #include -#include #include #include diff --git a/libs/gui/DebugEGLImageTracker.cpp b/libs/gui/DebugEGLImageTracker.cpp index ab6f36444a..5762dabc55 100644 --- a/libs/gui/DebugEGLImageTracker.cpp +++ b/libs/gui/DebugEGLImageTracker.cpp @@ -14,13 +14,14 @@ * limitations under the License. */ +#include #include -#include #include #include #include +using android::base::GetBoolProperty; using android::base::StringAppendF; std::mutex DebugEGLImageTracker::mInstanceLock; @@ -57,10 +58,7 @@ private: DebugEGLImageTracker *DebugEGLImageTracker::getInstance() { std::lock_guard lock(mInstanceLock); if (mInstance == nullptr) { - char value[PROPERTY_VALUE_MAX]; - property_get("debug.sf.enable_egl_image_tracker", value, "0"); - const bool enabled = static_cast(atoi(value)); - + const bool enabled = GetBoolProperty("debug.sf.enable_egl_image_tracker", false); if (enabled) { mInstance = new DebugEGLImageTrackerImpl(); } else { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d1d770e542..1acbc9ec1b 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 94ea7ac7e071de6904a3ec7c0deec7efac93b6e3 Mon Sep 17 00:00:00 2001 From: Hui Yu Date: Mon, 4 May 2020 17:40:52 +0000 Subject: Revert "Add isUidActiveOrForeground for camera/audio to use." Revert submission 10829580-isUidForeground Reason for revert: In CameraService.cpp, before this change, around "am.isUidActive", there was up to 300 ms retry. After this change, the code could move forward fast without retry, but at "mAppOpsManager->startOpNoThrow" call, for the same reason as uid is not updated fast enough, "mAppOpsManager->startOpNoThrow" could also fail. This CL does not really fix the root cause, but it changes the timing and now the code fails at "mAppOpsManager->startOpNoThrow" call. Also the timing change may also cause recent multiple CTS test failures. Bug: 154570809, 155032617, 154849083 Reverted Changes: Iffed63293:Add isUidActiveOrForeground() for camera/audio to ... I3685e0c8d:Add isUidActiveOrForeground() for camera/audio to ... I51ed1fe78:Add isUidActiveOrForeground for camera/audio to us... Change-Id: I9fbeb190c5a0ac640ad5be8140fe4aaeb7cfe33d --- libs/binder/ActivityManager.cpp | 9 ------- libs/binder/IActivityManager.cpp | 12 --------- libs/binder/include/binder/ActivityManager.h | 38 +++++++++++++-------------- libs/binder/include/binder/IActivityManager.h | 4 +-- 4 files changed, 20 insertions(+), 43 deletions(-) (limited to 'libs') diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp index 4f2709d91a..5e4c98fc7a 100644 --- a/libs/binder/ActivityManager.cpp +++ b/libs/binder/ActivityManager.cpp @@ -98,15 +98,6 @@ int32_t ActivityManager::getUidProcessState(const uid_t uid, const String16& cal return PROCESS_STATE_UNKNOWN; } -bool ActivityManager::isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) -{ - sp service = getService(); - if (service != nullptr) { - return service->isUidActiveOrForeground(uid, callingPackage); - } - return false; -} - status_t ActivityManager::linkToDeath(const sp& recipient) { sp service = getService(); if (service != nullptr) { diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp index 9e1249baf4..1eb5363ae2 100644 --- a/libs/binder/IActivityManager.cpp +++ b/libs/binder/IActivityManager.cpp @@ -104,18 +104,6 @@ public: } return reply.readInt32(); } - - virtual bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) - { - Parcel data, reply; - data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor()); - data.writeInt32(uid); - data.writeString16(callingPackage); - remote()->transact(IS_UID_ACTIVE_OR_FOREGROUND_TRANSACTION, data, &reply); - // fail on exception - if (reply.readExceptionCode() != 0) return false; - return reply.readInt32() == 1; - } }; // ------------------------------------------------------------------------------------ diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h index 0bb6d28da4..9108e31758 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include/binder/ActivityManager.h @@ -46,24 +46,25 @@ public: PROCESS_STATE_PERSISTENT = 0, PROCESS_STATE_PERSISTENT_UI = 1, PROCESS_STATE_TOP = 2, - PROCESS_STATE_BOUND_TOP = 3, - PROCESS_STATE_FOREGROUND_SERVICE = 4, - PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5, - PROCESS_STATE_IMPORTANT_FOREGROUND = 6, - PROCESS_STATE_IMPORTANT_BACKGROUND = 7, - PROCESS_STATE_TRANSIENT_BACKGROUND = 8, - PROCESS_STATE_BACKUP = 9, - PROCESS_STATE_SERVICE = 10, - PROCESS_STATE_RECEIVER = 11, - PROCESS_STATE_TOP_SLEEPING = 12, - PROCESS_STATE_HEAVY_WEIGHT = 13, - PROCESS_STATE_HOME = 14, - PROCESS_STATE_LAST_ACTIVITY = 15, - PROCESS_STATE_CACHED_ACTIVITY = 16, - PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17, - PROCESS_STATE_CACHED_RECENT = 18, - PROCESS_STATE_CACHED_EMPTY = 19, - PROCESS_STATE_NONEXISTENT = 20, + PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3, + PROCESS_STATE_BOUND_TOP = 4, + PROCESS_STATE_FOREGROUND_SERVICE = 5, + PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6, + PROCESS_STATE_IMPORTANT_FOREGROUND = 7, + PROCESS_STATE_IMPORTANT_BACKGROUND = 8, + PROCESS_STATE_TRANSIENT_BACKGROUND = 9, + PROCESS_STATE_BACKUP = 10, + PROCESS_STATE_SERVICE = 11, + PROCESS_STATE_RECEIVER = 12, + PROCESS_STATE_TOP_SLEEPING = 13, + PROCESS_STATE_HEAVY_WEIGHT = 14, + PROCESS_STATE_HOME = 15, + PROCESS_STATE_LAST_ACTIVITY = 16, + PROCESS_STATE_CACHED_ACTIVITY = 17, + PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18, + PROCESS_STATE_CACHED_RECENT = 19, + PROCESS_STATE_CACHED_EMPTY = 20, + PROCESS_STATE_NONEXISTENT = 21, }; ActivityManager(); @@ -76,7 +77,6 @@ public: void unregisterUidObserver(const sp& observer); bool isUidActive(const uid_t uid, const String16& callingPackage); int getUidProcessState(const uid_t uid, const String16& callingPackage); - bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage); status_t linkToDeath(const sp& recipient); diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h index 1815ecc67f..e0248f6624 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include/binder/IActivityManager.h @@ -39,15 +39,13 @@ public: virtual void unregisterUidObserver(const sp& observer) = 0; virtual bool isUidActive(const uid_t uid, const String16& callingPackage) = 0; virtual int32_t getUidProcessState(const uid_t uid, const String16& callingPackage) = 0; - virtual bool isUidActiveOrForeground(const uid_t uid, const String16& callingPackage) = 0; enum { OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, REGISTER_UID_OBSERVER_TRANSACTION, UNREGISTER_UID_OBSERVER_TRANSACTION, IS_UID_ACTIVE_TRANSACTION, - GET_UID_PROCESS_STATE_TRANSACTION, - IS_UID_ACTIVE_OR_FOREGROUND_TRANSACTION, + GET_UID_PROCESS_STATE_TRANSACTION }; }; -- cgit v1.2.3-59-g8ed1b From 9499a112e3a0ba25e8f5ff2049cc529c2982698f Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Mon, 4 May 2020 12:01:17 +0800 Subject: Makes TYPE_NOTIFICATION_SHADE as trusted overlay Fix the side effect after we split notification_shade window from status bar. Bug: 155373298 Test: follow the steps from b/149320322 Change-Id: I3362186b22505d21ec6e0ad779d4a26304ed782c Merged-In: I3362186b22505d21ec6e0ad779d4a26304ed782c --- include/input/InputWindow.h | 77 +++++++++++++++++++++++---------------------- libs/input/InputWindow.cpp | 19 ++++++----- 2 files changed, 48 insertions(+), 48 deletions(-) (limited to 'libs') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index a695a8ffda..856c54d89e 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -68,46 +68,47 @@ struct InputWindowInfo { // Window types from WindowManager.LayoutParams enum { FIRST_APPLICATION_WINDOW = 1, - TYPE_BASE_APPLICATION = 1, - TYPE_APPLICATION = 2, + TYPE_BASE_APPLICATION = 1, + TYPE_APPLICATION = 2, TYPE_APPLICATION_STARTING = 3, LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, - TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, - TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, - TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, - TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, - TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, - TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, - TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, - TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, - TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, - TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, - TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, - TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, - TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, - TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, - TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, - TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, - TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, - TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14, - TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, - TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, - TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17, - TYPE_POINTER = FIRST_SYSTEM_WINDOW+18, - TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, - TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, - TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, - TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22, - TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24, - TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27, - TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32, - TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34, - LAST_SYSTEM_WINDOW = 2999, + FIRST_SUB_WINDOW = 1000, + TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, + TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1, + TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2, + TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3, + TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4, + LAST_SUB_WINDOW = 1999, + FIRST_SYSTEM_WINDOW = 2000, + TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, + TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW + 1, + TYPE_PHONE = FIRST_SYSTEM_WINDOW + 2, + TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW + 3, + TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW + 4, + TYPE_TOAST = FIRST_SYSTEM_WINDOW + 5, + TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 6, + TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW + 7, + TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW + 8, + TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW + 9, + TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW + 10, + TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW + 11, + TYPE_INPUT_METHOD_DIALOG = FIRST_SYSTEM_WINDOW + 12, + TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW + 13, + TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW + 14, + TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW + 15, + TYPE_DRAG = FIRST_SYSTEM_WINDOW + 16, + TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW + 17, + TYPE_POINTER = FIRST_SYSTEM_WINDOW + 18, + TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW + 19, + TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW + 20, + TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW + 21, + TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW + 22, + TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW + 24, + TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 27, + TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, + TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, + TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, + LAST_SYSTEM_WINDOW = 2999, }; enum { diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index 6e4c97ded2..b27b050d28 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -43,16 +43,15 @@ bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { } bool InputWindowInfo::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD - || layoutParamsType == TYPE_INPUT_METHOD_DIALOG - || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY - || layoutParamsType == TYPE_STATUS_BAR - || layoutParamsType == TYPE_NAVIGATION_BAR - || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL - || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY - || layoutParamsType == TYPE_DOCK_DIVIDER - || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY - || layoutParamsType == TYPE_INPUT_CONSUMER; + return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || + layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR || + layoutParamsType == TYPE_NOTIFICATION_SHADE || + layoutParamsType == TYPE_NAVIGATION_BAR || + layoutParamsType == TYPE_NAVIGATION_BAR_PANEL || + layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY || + layoutParamsType == TYPE_DOCK_DIVIDER || + layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY || + layoutParamsType == TYPE_INPUT_CONSUMER; } bool InputWindowInfo::supportsSplitTouch() const { -- cgit v1.2.3-59-g8ed1b From fb9fcdae2f67ebef2ab6522fd2b49a57f9c28dd2 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 4 May 2020 14:59:19 -0700 Subject: Add test to call setInputWindows twice Currently, I'm observing some strange behaviour, where calling setInputWindows twice results in the touchable region becoming empty. Add this test to R to see what's going on, and potentially bisect on this. Bug: 143459140 Test: atest inputflinger_tests Change-Id: Ia0acef5d4ee4acc29d20174fe44c9f94172ccd96 --- libs/ui/Region.cpp | 5 ++ libs/ui/tests/Region_test.cpp | 15 +++++ .../inputflinger/tests/InputDispatcher_test.cpp | 73 ++++++++++++++++++---- 3 files changed, 82 insertions(+), 11 deletions(-) (limited to 'libs') diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index 82ce757d5a..e01309b679 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -224,6 +224,11 @@ Region& Region::operator = (const Region& rhs) validate(*this, "this->operator="); validate(rhs, "rhs.operator="); #endif + if (this == &rhs) { + // Already equal to itself + return *this; + } + mStorage.clear(); mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end()); return *this; diff --git a/libs/ui/tests/Region_test.cpp b/libs/ui/tests/Region_test.cpp index b104a46364..c6b826d66e 100644 --- a/libs/ui/tests/Region_test.cpp +++ b/libs/ui/tests/Region_test.cpp @@ -152,5 +152,20 @@ TEST_F(RegionTest, Random_TJunction) { } } +TEST_F(RegionTest, EqualsToSelf) { + Region touchableRegion; + touchableRegion.orSelf(Rect(0, 0, 100, 100)); + + ASSERT_TRUE(touchableRegion.contains(50, 50)); + + // Compiler prevents us from directly calling 'touchableRegion = touchableRegion' + Region& referenceTouchableRegion = touchableRegion; + touchableRegion = referenceTouchableRegion; + + ASSERT_FALSE(touchableRegion.isEmpty()); + + ASSERT_TRUE(touchableRegion.contains(50, 50)); +} + }; // namespace android diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 365d43dd16..e94737ff96 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -811,13 +811,15 @@ static int32_t injectMotionEvent(const sp& dispatcher, int32_t } static int32_t injectMotionDown(const sp& dispatcher, int32_t source, - int32_t displayId, int32_t x = 100, int32_t y = 200) { - return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y); + int32_t displayId, const PointF& location = {100, 200}) { + return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location.x, + location.y); } static int32_t injectMotionUp(const sp& dispatcher, int32_t source, - int32_t displayId, int32_t x = 100, int32_t y = 200) { - return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, x, y); + int32_t displayId, const PointF& location = {100, 200}) { + return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location.x, + location.y); } static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) { @@ -881,6 +883,55 @@ TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { window->consumeMotionDown(ADISPLAY_ID_DEFAULT); } +/** + * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues. + * To ensure that window receives only events that were directly inside of it, add + * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input + * when finding touched windows. + * This test serves as a sanity check for the next test, where setInputWindows is + * called twice. + */ +TEST_F(InputDispatcherTest, SetInputWindowOnce_SingleWindowTouch) { + sp application = new FakeApplicationHandle(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; + + // Window should receive motion event. + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); +} + +/** + * Calling setInputWindows twice, with the same info, should not cause any issues. + * To ensure that window receives only events that were directly inside of it, add + * FLAG_NOT_TOUCH_MODAL. This will enforce using the touchableRegion of the input + * when finding touched windows. + */ +TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { + sp application = new FakeApplicationHandle(); + sp window = + new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + window->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; + + // Window should receive motion event. + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); +} + // The foreground window should receive the first touch down event. TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { sp application = new FakeApplicationHandle(); @@ -1822,7 +1873,6 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL); - mFocusedWindowTouchPoint = 60; // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); @@ -1843,15 +1893,16 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { protected: sp mUnfocusedWindow; sp mFocusedWindow; - int32_t mFocusedWindowTouchPoint; + static constexpr PointF FOCUSED_WINDOW_TOUCH_POINT = {60, 60}; }; // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action // DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received // the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) { - ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20)) + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {20, 20})) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; mUnfocusedWindow->consumeMotionDown(); @@ -1863,8 +1914,8 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Succe // DOWN on the window that doesn't have focus. Ensure no window received the // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) { - ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, - AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20)) + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, {20, 20})) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; mFocusedWindow->consumeMotionDown(); @@ -1890,7 +1941,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - mFocusedWindowTouchPoint, mFocusedWindowTouchPoint)) + FOCUSED_WINDOW_TOUCH_POINT)) << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; mFocusedWindow->consumeMotionDown(); -- cgit v1.2.3-59-g8ed1b From 097c3db9fc66ffb6f1b55401229bcc43d885a3ed Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 6 May 2020 14:18:38 -0700 Subject: Use for input-related timeouts There is a lot of confusion in input tests about the units used for the timeouts. In a lot of cases, the timeouts are set too short, which causes failures when they start getting enforced. To avoid this, use std::chrono::duration for the timeouts. Ideally, we should convert InputWindowInfo and InputApplicationInfo to use std::chrono::nanoseconds, but that would be a larger change reserved for a future release. Bug: 143459140 Test: atest inputflinger_tests libinput_tests inputflinger_benchmarks Change-Id: Ie7536e8a042a71b372f03314501e0d635a6ac1d4 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 4 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 8 +-- .../inputflinger/dispatcher/InputDispatcher.cpp | 11 ++- services/inputflinger/dispatcher/InputDispatcher.h | 3 +- .../dispatcher/include/InputDispatcherInterface.h | 4 +- .../inputflinger/tests/InputDispatcher_test.cpp | 82 +++++++++++----------- 6 files changed, 56 insertions(+), 56 deletions(-) (limited to 'libs') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index c59afba87c..5188a09c4b 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -178,7 +178,7 @@ private: mInputInfo.name = "Test info"; mInputInfo.layoutParamsFlags = InputWindowInfo::FLAG_NOT_TOUCH_MODAL; mInputInfo.layoutParamsType = InputWindowInfo::TYPE_BASE_APPLICATION; - mInputInfo.dispatchingTimeout = 100000; + mInputInfo.dispatchingTimeout = seconds_to_nanoseconds(5); mInputInfo.globalScaleFactor = 1.0; mInputInfo.canReceiveKeys = true; mInputInfo.hasFocus = true; @@ -196,7 +196,7 @@ private: InputApplicationInfo aInfo; aInfo.token = new BBinder(); aInfo.name = "Test app info"; - aInfo.dispatchingTimeout = 100000; + aInfo.dispatchingTimeout = seconds_to_nanoseconds(5); mInputInfo.applicationInfo = aInfo; } diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 7c5c9c5f0c..2116cbcc7f 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -28,8 +28,8 @@ static const int32_t DEVICE_ID = 1; static const int32_t INJECTOR_PID = 999; static const int32_t INJECTOR_UID = 1001; -static const int32_t INJECT_EVENT_TIMEOUT = 5000; -static const int32_t DISPATCHING_TIMEOUT = 100000; +static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s; +static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms; static nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); @@ -98,7 +98,7 @@ public: virtual ~FakeApplicationHandle() {} virtual bool updateInfo() { - mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count(); return true; } }; @@ -163,7 +163,7 @@ public: mInfo.name = "FakeWindowHandle"; mInfo.layoutParamsFlags = 0; mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; - mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count(); mInfo.frameLeft = mFrame.left; mInfo.frameTop = mFrame.top; mInfo.frameRight = mFrame.right; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index baf2f2b917..2011551c38 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3273,14 +3273,14 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, - int32_t timeoutMillis, uint32_t policyFlags) { + std::chrono::milliseconds timeout, uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); + "syncMode=%d, timeout=%lld, policyFlags=0x%08x", + event->getType(), injectorPid, injectorUid, syncMode, timeout.count(), policyFlags); #endif - nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); + nsecs_t endTime = now() + std::chrono::duration_cast(timeout).count(); policyFlags |= POLICY_FLAG_INJECTED; if (hasInjectionPermission(injectorPid, injectorUid)) { @@ -3467,8 +3467,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injec } // release lock #if DEBUG_INJECTION - ALOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", + ALOGD("injectInputEvent - Finished with result %d. injectorPid=%d, injectorUid=%d", injectionResult, injectorPid, injectorUid); #endif diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 2b9cbcec2e..f6b5da3904 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -103,7 +103,8 @@ public: virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, - int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, + int32_t injectorUid, int32_t syncMode, + std::chrono::milliseconds timeout, uint32_t policyFlags) override; virtual std::unique_ptr verifyInputEvent(const InputEvent& event) override; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 09dc92c8fa..9b002f437c 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -90,8 +90,8 @@ public: * This method may be called on any thread (usually by the input manager). */ virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, - int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) = 0; + int32_t injectorUid, int32_t syncMode, + std::chrono::milliseconds timeout, uint32_t policyFlags) = 0; /* * Check whether InputEvent actually happened by checking the signature of the event. diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index e94737ff96..5db7b00bc3 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -313,18 +313,18 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { INVALID_HMAC, /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject key events with undefined action."; // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API. event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, AKEY_EVENT_ACTION_MULTIPLE, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject key events with ACTION_MULTIPLE."; } @@ -350,9 +350,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 1 /* yScale */, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with undefined action."; // Rejects pointer down with invalid index. @@ -363,9 +363,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with pointer down index too large."; event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, @@ -375,9 +375,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with pointer down index too small."; // Rejects pointer up with invalid index. @@ -388,9 +388,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with pointer up index too large."; event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, @@ -400,9 +400,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with pointer up index too small."; // Rejects motion events with invalid number of pointers. @@ -412,9 +412,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with 0 pointers."; event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, @@ -423,9 +423,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with more than MAX_POINTERS pointers."; // Rejects motion events with invalid pointer ids. @@ -436,9 +436,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with pointer ids less than 0."; pointerProperties[0].id = MAX_POINTER_ID + 1; @@ -448,9 +448,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with pointer ids greater than MAX_POINTER_ID."; // Rejects motion events with duplicate pointer ids. @@ -462,9 +462,9 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords); - ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0)) + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, + INPUT_EVENT_INJECTION_SYNC_NONE, 0ms, 0)) << "Should reject motion events with duplicate pointer ids."; } @@ -490,16 +490,16 @@ TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) { } // --- InputDispatcherTest SetInputWindowTest --- -static constexpr int32_t INJECT_EVENT_TIMEOUT = 500; -static constexpr nsecs_t DISPATCHING_TIMEOUT = seconds_to_nanoseconds(5); +static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms; +static constexpr std::chrono::duration DISPATCHING_TIMEOUT = 5s; class FakeApplicationHandle : public InputApplicationHandle { public: FakeApplicationHandle() {} virtual ~FakeApplicationHandle() {} - virtual bool updateInfo() { - mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + virtual bool updateInfo() override { + mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count(); return true; } }; @@ -638,7 +638,7 @@ public: mInfo.name = name; mInfo.layoutParamsFlags = 0; mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION; - mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; + mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count(); mInfo.frameLeft = 0; mInfo.frameTop = 0; mInfo.frameRight = WIDTH; -- cgit v1.2.3-59-g8ed1b From 466cdea8d2de302f6be4d9f59816dd2c6078decf Mon Sep 17 00:00:00 2001 From: Joshua Tsuji Date: Mon, 4 May 2020 13:53:00 -0400 Subject: Make TYPE_TRUSTED_APPLICATION_OVERLAY a trusted overlay. Test: accept a permission dialog while bubbles are there too Fixes: 149320322 Change-Id: I3767e2d93d0bcb216483a12d94ffb13ca0051c7e --- include/input/InputWindow.h | 1 + libs/input/InputWindow.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h index 856c54d89e..c5e56fd91f 100644 --- a/include/input/InputWindow.h +++ b/include/input/InputWindow.h @@ -108,6 +108,7 @@ struct InputWindowInfo { TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW + 32, TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW + 34, TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40, + TYPE_TRUSTED_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 42, LAST_SYSTEM_WINDOW = 2999, }; diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp index b27b050d28..85a2015e43 100644 --- a/libs/input/InputWindow.cpp +++ b/libs/input/InputWindow.cpp @@ -42,6 +42,7 @@ bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { && y >= frameTop && y < frameBottom; } +// TODO(b/155781676): Remove and replace call points with trustedOverlay when that is ready. bool InputWindowInfo::isTrustedOverlay() const { return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY || layoutParamsType == TYPE_STATUS_BAR || @@ -51,7 +52,8 @@ bool InputWindowInfo::isTrustedOverlay() const { layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY || layoutParamsType == TYPE_DOCK_DIVIDER || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY || - layoutParamsType == TYPE_INPUT_CONSUMER; + layoutParamsType == TYPE_INPUT_CONSUMER || + layoutParamsType == TYPE_TRUSTED_APPLICATION_OVERLAY; } bool InputWindowInfo::supportsSplitTouch() const { -- cgit v1.2.3-59-g8ed1b From 401cda638e7d17f6697b5a65c9a5ad79d056202d Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 7 May 2020 16:04:41 -0700 Subject: Add hook for intercepting query Bug: 143555869 Test: verified no kgsl maps in RenderThread Change-Id: Ifac5869cd6b29570286f8fd2aa641701f77fde94 --- libs/gui/Surface.cpp | 28 ++++++++++++++++++++++++- libs/gui/include/gui/Surface.h | 6 +++++- libs/nativewindow/include/system/window.h | 35 +++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index f911e70ebf..2bf8ff7581 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -57,7 +57,8 @@ bool isInterceptorRegistrationOp(int op) { return op == NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR || op == NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR || op == NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR || - op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR; + op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR || + op == NATIVE_WINDOW_SET_QUERY_INTERCEPTOR; } } // namespace @@ -500,6 +501,19 @@ int Surface::performInternal(ANativeWindow* window, int operation, va_list args) } int Surface::hook_query(const ANativeWindow* window, int what, int* value) { + const Surface* c = getSelf(window); + { + std::shared_lock lock(c->mInterceptorMutex); + if (c->mQueryInterceptor != nullptr) { + auto interceptor = c->mQueryInterceptor; + auto data = c->mQueryInterceptorData; + return interceptor(window, Surface::queryInternal, data, what, value); + } + } + return c->query(what, value); +} + +int Surface::queryInternal(const ANativeWindow* window, int what, int* value) { const Surface* c = getSelf(window); return c->query(what, value); } @@ -1177,6 +1191,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR: res = dispatchAddQueueInterceptor(args); break; + case NATIVE_WINDOW_SET_QUERY_INTERCEPTOR: + res = dispatchAddQueryInterceptor(args); + break; case NATIVE_WINDOW_ALLOCATE_BUFFERS: allocateBuffers(); res = NO_ERROR; @@ -1457,6 +1474,15 @@ int Surface::dispatchAddQueueInterceptor(va_list args) { return NO_ERROR; } +int Surface::dispatchAddQueryInterceptor(va_list args) { + ANativeWindow_queryInterceptor interceptor = va_arg(args, ANativeWindow_queryInterceptor); + void* data = va_arg(args, void*); + std::lock_guard lock(mInterceptorMutex); + mQueryInterceptor = interceptor; + mQueryInterceptorData = data; + return NO_ERROR; +} + int Surface::dispatchGetLastQueuedBuffer(va_list args) { AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**); int* fence = va_arg(args, int*); diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 917c0d4831..49c83da319 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -209,6 +209,7 @@ private: int* fenceFd); static int performInternal(ANativeWindow* window, int operation, va_list args); static int queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd); + static int queryInternal(const ANativeWindow* window, int what, int* value); static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer); @@ -261,6 +262,7 @@ private: int dispatchAddDequeueInterceptor(va_list args); int dispatchAddPerformInterceptor(va_list args); int dispatchAddQueueInterceptor(va_list args); + int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); bool transformToDisplayInverse(); @@ -468,7 +470,7 @@ protected: mutable Mutex mMutex; // mInterceptorMutex is the mutex guarding interceptors. - std::shared_mutex mInterceptorMutex; + mutable std::shared_mutex mInterceptorMutex; ANativeWindow_cancelBufferInterceptor mCancelInterceptor = nullptr; void* mCancelInterceptorData = nullptr; @@ -478,6 +480,8 @@ protected: void* mPerformInterceptorData = nullptr; ANativeWindow_queueBufferInterceptor mQueueInterceptor = nullptr; void* mQueueInterceptorData = nullptr; + ANativeWindow_queryInterceptor mQueryInterceptor = nullptr; + void* mQueryInterceptorData = nullptr; // must be used from the lock/unlock thread sp mLockedBuffer; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 869ca9ebe3..b78fc5dbbc 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -254,6 +254,7 @@ enum { NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */ NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */ NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ + NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ // clang-format on }; @@ -1062,4 +1063,38 @@ static inline int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) { return value; } +/** + * Prototype of the function that an ANativeWindow implementation would call + * when ANativeWindow_query is called. + */ +typedef int (*ANativeWindow_queryFn)(const ANativeWindow* window, int what, int* value); + +/** + * Prototype of the function that intercepts an invocation of + * ANativeWindow_queryFn, along with a data pointer that's passed by the + * caller who set the interceptor, as well as arguments that would be + * passed to ANativeWindow_queryFn if it were to be called. + */ +typedef int (*ANativeWindow_queryInterceptor)(const ANativeWindow* window, + ANativeWindow_queryFn perform, void* data, + int what, int* value); + +/** + * Registers an interceptor for ANativeWindow_query. Instead of calling + * the underlying query function, instead the provided interceptor is + * called, which may optionally call the underlying query function. An + * optional data pointer is also provided to side-channel additional arguments. + * + * Note that usage of this should only be used for specialized use-cases by + * either the system partition or to Mainline modules. This should never be + * exposed to NDK or LL-NDK. + * + * Returns NO_ERROR on success, -errno if registration failed. + */ +static inline int ANativeWindow_setQueryInterceptor(ANativeWindow* window, + ANativeWindow_queryInterceptor interceptor, + void* data) { + return window->perform(window, NATIVE_WINDOW_SET_QUERY_INTERCEPTOR, interceptor, data); +} + __END_DECLS -- cgit v1.2.3-59-g8ed1b From 271de040ffc1371251a9741d2f347642a5de0995 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 27 Apr 2020 22:38:19 -0700 Subject: Receive refresh rate callbacks from DMS AChoreographer will use DMS as the source of truth for these callbacks instead of SurfaceFlinger. Bug: 154874011 Test: ChoreographerNativeTest Tes: Manually verify that HWUI is processing refresh rate callbacks Change-Id: I961a7d1ab335800d3e260ba7564ddca9c0595cfc --- include/android/choreographer.h | 156 ++++++++++ libs/gui/DisplayEventDispatcher.cpp | 13 +- libs/gui/DisplayEventReceiver.cpp | 5 +- libs/gui/IDisplayEventConnection.cpp | 15 +- libs/gui/include/gui/DisplayEventDispatcher.h | 3 +- libs/gui/include/gui/DisplayEventReceiver.h | 5 +- libs/gui/include/gui/IDisplayEventConnection.h | 6 +- libs/nativedisplay/AChoreographer.cpp | 324 +++++++++++++++++---- libs/nativedisplay/Android.bp | 17 +- .../private/android/choreographer.h | 55 ++++ libs/nativedisplay/include/android/choreographer.h | 152 ---------- .../surfacetexture/surface_texture_platform.h | 16 +- libs/nativedisplay/libnativedisplay.map.txt | 17 ++ .../surfacetexture/surface_texture.cpp | 31 ++ services/surfaceflinger/Scheduler/EventThread.cpp | 27 +- services/surfaceflinger/Scheduler/EventThread.h | 11 +- .../tests/unittests/mock/MockEventThread.h | 2 +- 17 files changed, 585 insertions(+), 270 deletions(-) create mode 100644 include/android/choreographer.h create mode 100644 libs/nativedisplay/include-private/private/android/choreographer.h delete mode 100644 libs/nativedisplay/include/android/choreographer.h (limited to 'libs') diff --git a/include/android/choreographer.h b/include/android/choreographer.h new file mode 100644 index 0000000000..c1c4a72cd3 --- /dev/null +++ b/include/android/choreographer.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @addtogroup Choreographer + * @{ + */ + +/** + * @file choreographer.h + */ + +#ifndef ANDROID_CHOREOGRAPHER_H +#define ANDROID_CHOREOGRAPHER_H + +#include +#include + +__BEGIN_DECLS + +struct AChoreographer; +typedef struct AChoreographer AChoreographer; + +/** + * Prototype of the function that is called when a new frame is being rendered. + * It's passed the time that the frame is being rendered as nanoseconds in the + * CLOCK_MONOTONIC time base, as well as the data pointer provided by the + * application that registered a callback. All callbacks that run as part of + * rendering a frame will observe the same frame time, so it should be used + * whenever events need to be synchronized (e.g. animations). + */ +typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data); + +/** + * Prototype of the function that is called when a new frame is being rendered. + * It's passed the time that the frame is being rendered as nanoseconds in the + * CLOCK_MONOTONIC time base, as well as the data pointer provided by the + * application that registered a callback. All callbacks that run as part of + * rendering a frame will observe the same frame time, so it should be used + * whenever events need to be synchronized (e.g. animations). + */ +typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data); + +/** + * Prototype of the function that is called when the display refresh rate + * changes. It's passed the new vsync period in nanoseconds, as well as the data + * pointer provided by the application that registered a callback. + */ +typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data); + +#if __ANDROID_API__ >= 24 + +/** + * Get the AChoreographer instance for the current thread. This must be called + * on an ALooper thread. + * + * Available since API level 24. + */ +AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24); + +/** + * Deprecated: Use AChoreographer_postFrameCallback64 instead. + */ +void AChoreographer_postFrameCallback(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data) + __INTRODUCED_IN(24) __DEPRECATED_IN(29); + +/** + * Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead. + */ +void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data, + long delayMillis) __INTRODUCED_IN(24) + __DEPRECATED_IN(29); + +#endif /* __ANDROID_API__ >= 24 */ + +#if __ANDROID_API__ >= 29 + +/** + * Power a callback to be run on the next frame. The data pointer provided will + * be passed to the callback function when it's called. + * + * Available since API level 29. + */ +void AChoreographer_postFrameCallback64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, void* data) + __INTRODUCED_IN(29); + +/** + * Post a callback to be run on the frame following the specified delay. The + * data pointer provided will be passed to the callback function when it's + * called. + * + * Available since API level 29. + */ +void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, void* data, + uint32_t delayMillis) __INTRODUCED_IN(29); + +#endif /* __ANDROID_API__ >= 29 */ + +#if __ANDROID_API__ >= 30 + +/** + * Registers a callback to be run when the display refresh rate changes. The + * data pointer provided will be passed to the callback function when it's + * called. The same callback may be registered multiple times, provided that a + * different data pointer is provided each time. + * + * If an application registers a callback for this choreographer instance when + * no new callbacks were previously registered, that callback is guaranteed to + * be dispatched. However, if the callback and associated data pointer are + * unregistered prior to running the callback, then the callback may be silently + * dropped. + * + * This api is thread-safe. Any thread is allowed to register a new refresh + * rate callback for the choreographer instance. + */ +void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback, void* data); + +/** + * Unregisters a callback to be run when the display refresh rate changes, along + * with the data pointer previously provided when registering the callback. The + * callback is only unregistered when the data pointer matches one that was + * previously registered. + * + * This api is thread-safe. Any thread is allowed to unregister an existing + * refresh rate callback for the choreographer instance. When a refresh rate + * callback and associated data pointer are unregistered, then there is a + * guarantee that when the unregistration completes that that callback will not + * be run with the data pointer passed. + */ +void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback, void* data); +#endif /* __ANDROID_API__ >= 30 */ + +__END_DECLS + +#endif // ANDROID_CHOREOGRAPHER_H + +/** @} */ diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 15f966d062..b33bc9e556 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -36,10 +36,7 @@ static const size_t EVENT_BUFFER_SIZE = 100; DisplayEventDispatcher::DisplayEventDispatcher(const sp& looper, ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) - : mLooper(looper), - mReceiver(vsyncSource, configChanged), - mWaitingForVsync(false), - mConfigChangeFlag(configChanged) { + : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) { ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this); } @@ -92,16 +89,12 @@ status_t DisplayEventDispatcher::scheduleVsync() { return OK; } -void DisplayEventDispatcher::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) { - if (mConfigChangeFlag == configChangeFlag) { - return; - } - status_t status = mReceiver.toggleConfigEvents(configChangeFlag); +void DisplayEventDispatcher::requestLatestConfig() { + status_t status = mReceiver.requestLatestConfig(); if (status) { ALOGW("Failed enable config events, status=%d", status); return; } - mConfigChangeFlag = configChangeFlag; } int DisplayEventDispatcher::getFd() const { diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index fd6aaf8b46..1fed509003 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -79,10 +79,9 @@ status_t DisplayEventReceiver::requestNextVsync() { return NO_INIT; } -status_t DisplayEventReceiver::toggleConfigEvents( - ISurfaceComposer::ConfigChanged configChangeFlag) { +status_t DisplayEventReceiver::requestLatestConfig() { if (mEventConnection != nullptr) { - mEventConnection->toggleConfigEvents(configChangeFlag); + mEventConnection->requestLatestConfig(); return NO_ERROR; } return NO_INIT; diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp index dda5acf8a7..aa74bfd3f8 100644 --- a/libs/gui/IDisplayEventConnection.cpp +++ b/libs/gui/IDisplayEventConnection.cpp @@ -26,8 +26,8 @@ enum class Tag : uint32_t { STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, SET_VSYNC_RATE, REQUEST_NEXT_VSYNC, - TOGGLE_CONFIG_EVENTS, - LAST = TOGGLE_CONFIG_EVENTS, + REQUEST_LATEST_CONFIG, + LAST = REQUEST_LATEST_CONFIG, }; } // Anonymous namespace @@ -55,10 +55,9 @@ public: Tag::REQUEST_NEXT_VSYNC); } - void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override { - callRemoteAsync(Tag::TOGGLE_CONFIG_EVENTS, - configChangeFlag); + void requestLatestConfig() override { + callRemoteAsync( + Tag::REQUEST_LATEST_CONFIG); } }; @@ -81,8 +80,8 @@ status_t BnDisplayEventConnection::onTransact(uint32_t code, const Parcel& data, return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate); case Tag::REQUEST_NEXT_VSYNC: return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync); - case Tag::TOGGLE_CONFIG_EVENTS: - return callLocalAsync(data, reply, &IDisplayEventConnection::toggleConfigEvents); + case Tag::REQUEST_LATEST_CONFIG: + return callLocalAsync(data, reply, &IDisplayEventConnection::requestLatestConfig); } } diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index fcdf6bfa7e..f210c34196 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -31,7 +31,7 @@ public: status_t initialize(); void dispose(); status_t scheduleVsync(); - void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag); + void requestLatestConfig(); int getFd() const; virtual int handleEvent(int receiveFd, int events, void* data); @@ -42,7 +42,6 @@ private: sp mLooper; DisplayEventReceiver mReceiver; bool mWaitingForVsync; - ISurfaceComposer::ConfigChanged mConfigChangeFlag; virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0; virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index d9a0253781..8d49184caf 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -147,9 +147,10 @@ public: status_t requestNextVsync(); /* - * toggleConfigEvents() toggles delivery of config change events. + * requestLatestConfig() force-requests the current config for the primary + * display. */ - status_t toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag); + status_t requestLatestConfig(); private: sp mEventConnection; diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h index 8b35ef6486..674aafd81c 100644 --- a/libs/gui/include/gui/IDisplayEventConnection.h +++ b/libs/gui/include/gui/IDisplayEventConnection.h @@ -53,11 +53,9 @@ public: virtual void requestNextVsync() = 0; // Asynchronous /* - * togglesConfigEvents() configures whether or not display config changes - * should be propagated. + * requestLatestConfig() requests the config for the primary display. */ - virtual void toggleConfigEvents( - ISurfaceComposer::ConfigChanged configChangeFlag) = 0; // Asynchronous + virtual void requestLatestConfig() = 0; // Asynchronous }; class BnDisplayEventConnection : public SafeBnInterface { diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 0ff33ac747..ea51245ac6 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -17,24 +17,63 @@ #define LOG_TAG "Choreographer" //#define LOG_NDEBUG 0 -#include +#include #include #include #include +#include +#include #include -#include #include #include +#include #include #include #include -namespace android { +namespace { +struct { + // Global JVM that is provided by zygote + JavaVM* jvm = nullptr; + struct { + jclass clazz; + jmethodID getInstance; + jmethodID registerNativeChoreographerForRefreshRateCallbacks; + jmethodID unregisterNativeChoreographerForRefreshRateCallbacks; + } displayManagerGlobal; +} gJni; + +// Gets the JNIEnv* for this thread, and performs one-off initialization if we +// have never retrieved a JNIEnv* pointer before. +JNIEnv* getJniEnv() { + if (gJni.jvm == nullptr) { + ALOGW("AChoreographer: No JVM provided!"); + return nullptr; + } + + JNIEnv* env = nullptr; + if (gJni.jvm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) { + ALOGD("Attaching thread to JVM for AChoreographer"); + JavaVMAttachArgs args = {JNI_VERSION_1_4, "AChoreographer_env", NULL}; + jint attachResult = gJni.jvm->AttachCurrentThreadAsDaemon(&env, (void*)&args); + if (attachResult != JNI_OK) { + ALOGE("Unable to attach thread. Error: %d", attachResult); + return nullptr; + } + } + if (env == nullptr) { + ALOGW("AChoreographer: No JNI env available!"); + } + return env; +} -static inline const char* toString(bool value) { +inline const char* toString(bool value) { return value ? "true" : "false"; } +} // namespace + +namespace android { struct FrameCallback { AChoreographer_frameCallback callback; @@ -52,24 +91,43 @@ struct FrameCallback { struct RefreshRateCallback { AChoreographer_refreshRateCallback callback; void* data; + bool firstCallbackFired = false; }; +class Choreographer; + +struct { + std::mutex lock; + std::vector ptrs GUARDED_BY(lock); + bool registeredToDisplayManager GUARDED_BY(lock) = false; + + std::atomic mLastKnownVsync = -1; +} gChoreographers; + class Choreographer : public DisplayEventDispatcher, public MessageHandler { public: - explicit Choreographer(const sp& looper); + explicit Choreographer(const sp& looper) EXCLUDES(gChoreographers.lock); void postFrameCallbackDelayed(AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay); - void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); + void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) + EXCLUDES(gChoreographers.lock); void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data); + // Drains the queue of pending vsync periods and dispatches refresh rate + // updates to callbacks. + // The assumption is that this method is only called on a single + // processing thread, either by looper or by AChoreographer_handleEvents + void handleRefreshRateUpdates(); + void scheduleLatestConfigRequest(); enum { MSG_SCHEDULE_CALLBACKS = 0, - MSG_SCHEDULE_VSYNC = 1 + MSG_SCHEDULE_VSYNC = 1, + MSG_HANDLE_REFRESH_RATE_UPDATES = 2, }; virtual void handleMessage(const Message& message) override; static Choreographer* getForThread(); - virtual ~Choreographer() = default; + virtual ~Choreographer() override EXCLUDES(gChoreographers.lock); private: Choreographer(const Choreographer&) = delete; @@ -81,21 +139,17 @@ private: void scheduleCallbacks(); + std::mutex mLock; // Protected by mLock std::priority_queue mFrameCallbacks; - - // Protected by mLock std::vector mRefreshRateCallbacks; - nsecs_t mVsyncPeriod = 0; - mutable Mutex mLock; + nsecs_t mLatestVsyncPeriod = -1; const sp mLooper; const std::thread::id mThreadId; - const std::optional mInternalDisplayId; }; - static thread_local Choreographer* gChoreographer; Choreographer* Choreographer::getForThread() { if (gChoreographer == nullptr) { @@ -115,17 +169,47 @@ Choreographer* Choreographer::getForThread() { } Choreographer::Choreographer(const sp& looper) - : DisplayEventDispatcher(looper), + : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp, + ISurfaceComposer::ConfigChanged::eConfigChangedDispatch), mLooper(looper), - mThreadId(std::this_thread::get_id()), - mInternalDisplayId(SurfaceComposerClient::getInternalDisplayId()) {} + mThreadId(std::this_thread::get_id()) { + std::lock_guard _l(gChoreographers.lock); + gChoreographers.ptrs.push_back(this); +} + +Choreographer::~Choreographer() { + std::lock_guard _l(gChoreographers.lock); + gChoreographers.ptrs.erase(std::remove_if(gChoreographers.ptrs.begin(), + gChoreographers.ptrs.end(), + [=](Choreographer* c) { return c == this; }), + gChoreographers.ptrs.end()); + // Only poke DisplayManagerGlobal to unregister if we previously registered + // callbacks. + if (gChoreographers.ptrs.empty() && gChoreographers.registeredToDisplayManager) { + JNIEnv* env = getJniEnv(); + if (env == nullptr) { + ALOGW("JNI environment is unavailable, skipping choreographer cleanup"); + return; + } + jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, + gJni.displayManagerGlobal.getInstance); + if (dmg == nullptr) { + ALOGW("DMS is not initialized yet, skipping choreographer cleanup"); + } else { + env->CallVoidMethod(dmg, + gJni.displayManagerGlobal + .unregisterNativeChoreographerForRefreshRateCallbacks); + env->DeleteLocalRef(dmg); + } + } +} void Choreographer::postFrameCallbackDelayed( AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); FrameCallback callback{cb, cb64, data, now + delay}; { - AutoMutex _l{mLock}; + std::lock_guard _l{mLock}; mFrameCallbacks.push(callback); } if (callback.dueTime <= now) { @@ -150,37 +234,68 @@ void Choreographer::postFrameCallbackDelayed( } void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) { + std::lock_guard _l{mLock}; + for (const auto& callback : mRefreshRateCallbacks) { + // Don't re-add callbacks. + if (cb == callback.callback && data == callback.data) { + return; + } + } + mRefreshRateCallbacks.emplace_back( + RefreshRateCallback{.callback = cb, .data = data, .firstCallbackFired = false}); + bool needsRegistration = false; { - AutoMutex _l{mLock}; - for (const auto& callback : mRefreshRateCallbacks) { - // Don't re-add callbacks. - if (cb == callback.callback && data == callback.data) { - return; + std::lock_guard _l2(gChoreographers.lock); + needsRegistration = !gChoreographers.registeredToDisplayManager; + } + if (needsRegistration) { + JNIEnv* env = getJniEnv(); + jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, + gJni.displayManagerGlobal.getInstance); + if (env == nullptr) { + ALOGW("JNI environment is unavailable, skipping registeration"); + return; + } + if (dmg == nullptr) { + ALOGW("DMS is not initialized yet: skipping registration"); + return; + } else { + env->CallVoidMethod(dmg, + gJni.displayManagerGlobal + .registerNativeChoreographerForRefreshRateCallbacks, + reinterpret_cast(this)); + env->DeleteLocalRef(dmg); + { + std::lock_guard _l2(gChoreographers.lock); + gChoreographers.registeredToDisplayManager = true; } } - mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data}); - toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch); + } else { + scheduleLatestConfigRequest(); } } void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) { - { - AutoMutex _l{mLock}; - mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(), - mRefreshRateCallbacks.end(), - [&](const RefreshRateCallback& callback) { - return cb == callback.callback && - data == callback.data; - }), - mRefreshRateCallbacks.end()); - if (mRefreshRateCallbacks.empty()) { - toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress); - // If callbacks are empty then clear out the most recently seen - // vsync period so that when another callback is registered then the - // up-to-date refresh rate can be communicated to the app again. - mVsyncPeriod = 0; - } + std::lock_guard _l{mLock}; + mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(), + mRefreshRateCallbacks.end(), + [&](const RefreshRateCallback& callback) { + return cb == callback.callback && + data == callback.data; + }), + mRefreshRateCallbacks.end()); +} + +void Choreographer::scheduleLatestConfigRequest() { + if (mLooper != nullptr) { + Message m{MSG_HANDLE_REFRESH_RATE_UPDATES}; + mLooper->sendMessage(this, m); + } else { + // If the looper thread is detached from Choreographer, then refresh rate + // changes will be handled in AChoreographer_handlePendingEvents, so we + // need to redispatch a config from SF + requestLatestConfig(); } } @@ -188,7 +303,7 @@ void Choreographer::scheduleCallbacks() { const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); nsecs_t dueTime; { - AutoMutex _{mLock}; + std::lock_guard _l{mLock}; // If there are no pending callbacks then don't schedule a vsync if (mFrameCallbacks.empty()) { return; @@ -203,13 +318,35 @@ void Choreographer::scheduleCallbacks() { } } +void Choreographer::handleRefreshRateUpdates() { + std::vector callbacks{}; + const nsecs_t pendingPeriod = gChoreographers.mLastKnownVsync.load(); + const nsecs_t lastPeriod = mLatestVsyncPeriod; + if (pendingPeriod > 0) { + mLatestVsyncPeriod = pendingPeriod; + } + { + std::lock_guard _l{mLock}; + for (auto& cb : mRefreshRateCallbacks) { + callbacks.push_back(cb); + cb.firstCallbackFired = true; + } + } + + for (auto& cb : callbacks) { + if (!cb.firstCallbackFired || (pendingPeriod > 0 && pendingPeriod != lastPeriod)) { + cb.callback(pendingPeriod, cb.data); + } + } +} + // TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the // internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for // the internal display implicitly. void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) { std::vector callbacks{}; { - AutoMutex _l{mLock}; + std::lock_guard _l{mLock}; nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) { callbacks.push_back(mFrameCallbacks.top()); @@ -236,20 +373,29 @@ void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool c // display, so as such Choreographer does not support the notion of multiple // displays. When multi-display choreographer is properly supported, then // PhysicalDisplayId should no longer be ignored. -void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t, +void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId, int32_t configId, nsecs_t vsyncPeriod) { + ALOGV("choreographer %p ~ received config change event " + "(displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%d).", + this, displayId, configId); + + const nsecs_t lastPeriod = mLatestVsyncPeriod; + std::vector callbacks{}; { - AutoMutex _l{mLock}; - for (const auto& cb : mRefreshRateCallbacks) { - // Only perform the callback when the old refresh rate is different - // from the new refresh rate, so that we don't dispatch the callback - // on every single configuration change. - if (mVsyncPeriod != vsyncPeriod) { - cb.callback(vsyncPeriod, cb.data); - } + std::lock_guard _l{mLock}; + for (auto& cb : mRefreshRateCallbacks) { + callbacks.push_back(cb); + cb.firstCallbackFired = true; + } + } + + for (auto& cb : callbacks) { + if (!cb.firstCallbackFired || (vsyncPeriod > 0 && vsyncPeriod != lastPeriod)) { + cb.callback(vsyncPeriod, cb.data); } - mVsyncPeriod = vsyncPeriod; } + + mLatestVsyncPeriod = vsyncPeriod; } void Choreographer::handleMessage(const Message& message) { @@ -260,19 +406,80 @@ void Choreographer::handleMessage(const Message& message) { case MSG_SCHEDULE_VSYNC: scheduleVsync(); break; + case MSG_HANDLE_REFRESH_RATE_UPDATES: + handleRefreshRateUpdates(); + break; } } -} - -/* Glue for the NDK interface */ - +} // namespace android using namespace android; static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) { return reinterpret_cast(choreographer); } +// Glue for private C api +namespace android { +void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) { + std::lock_guard _l(gChoreographers.lock); + gChoreographers.mLastKnownVsync.store(vsyncPeriod); + for (auto c : gChoreographers.ptrs) { + c->scheduleLatestConfigRequest(); + } +} + +void AChoreographer_initJVM(JNIEnv* env) { + env->GetJavaVM(&gJni.jvm); + // Now we need to find the java classes. + jclass dmgClass = env->FindClass("android/hardware/display/DisplayManagerGlobal"); + gJni.displayManagerGlobal.clazz = static_cast(env->NewGlobalRef(dmgClass)); + gJni.displayManagerGlobal.getInstance = + env->GetStaticMethodID(dmgClass, "getInstance", + "()Landroid/hardware/display/DisplayManagerGlobal;"); + gJni.displayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks = + env->GetMethodID(dmgClass, "registerNativeChoreographerForRefreshRateCallbacks", "()V"); + gJni.displayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks = + env->GetMethodID(dmgClass, "unregisterNativeChoreographerForRefreshRateCallbacks", + "()V"); +} + +AChoreographer* AChoreographer_routeGetInstance() { + return AChoreographer_getInstance(); +} +void AChoreographer_routePostFrameCallback(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data) { + return AChoreographer_postFrameCallback(choreographer, callback, data); +} +void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data, + long delayMillis) { + return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis); +} +void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, void* data) { + return AChoreographer_postFrameCallback64(choreographer, callback, data); +} +void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, + void* data, uint32_t delayMillis) { + return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis); +} +void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback callback, + void* data) { + return AChoreographer_registerRefreshRateCallback(choreographer, callback, data); +} +void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback callback, + void* data) { + return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data); +} + +} // namespace android + +/* Glue for the NDK interface */ + static inline const Choreographer* AChoreographer_to_Choreographer( const AChoreographer* choreographer) { return reinterpret_cast(choreographer); @@ -343,5 +550,6 @@ void AChoreographer_handlePendingEvents(AChoreographer* choreographer, void* dat // Pass dummy fd and events args to handleEvent, since the underlying // DisplayEventDispatcher doesn't need them outside of validating that a // Looper instance didn't break, but these args circumvent those checks. - AChoreographer_to_Choreographer(choreographer)->handleEvent(-1, Looper::EVENT_INPUT, data); + Choreographer* impl = AChoreographer_to_Choreographer(choreographer); + impl->handleEvent(-1, Looper::EVENT_INPUT, data); } diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp index c9565780e0..f56b3a2178 100644 --- a/libs/nativedisplay/Android.bp +++ b/libs/nativedisplay/Android.bp @@ -12,23 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -ndk_headers { - name: "libnativedisplay_ndk_headers", - from: "include/android", - to: "android", - srcs: ["include/android/*.h"], - license: "NOTICE", -} - cc_library_headers { name: "libnativedisplay_headers", - export_include_dirs: ["include"], + export_include_dirs: ["include",], } -cc_library { +cc_library_shared { name: "libnativedisplay", export_include_dirs: [ "include", + "include-private", ], clang: true, @@ -63,6 +56,10 @@ cc_library { "libnativehelper", ], + export_shared_lib_headers: [ + "libnativehelper", + ], + header_libs: [ "libnativedisplay_headers", ], diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h new file mode 100644 index 0000000000..21649304bf --- /dev/null +++ b/libs/nativedisplay/include-private/private/android/choreographer.h @@ -0,0 +1,55 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +namespace android { + +// Registers the global JVM for AChoreographer +void AChoreographer_initJVM(JNIEnv* env); + +// Signals all AChoregorapher* instances that a new vsync period is available +// for consumption by callbacks. +void AChoreographer_signalRefreshRateCallbacks(int64_t vsyncPeriod); + +// Trampoline functions allowing libandroid.so to define the NDK symbols without including +// the entirety of libnativedisplay as a whole static lib. As libnativedisplay +// maintains global state, libnativedisplay can never be directly statically +// linked so that global state won't be duplicated. This way libandroid.so can +// reroute the NDK methods into the implementations defined by libnativedisplay +AChoreographer* AChoreographer_routeGetInstance(); +void AChoreographer_routePostFrameCallback(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data); +void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer, + AChoreographer_frameCallback callback, void* data, + long delayMillis); +void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, void* data); +void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer, + AChoreographer_frameCallback64 callback, + void* data, uint32_t delayMillis); +void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback callback, + void* data); +void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer, + AChoreographer_refreshRateCallback callback, + void* data); + +} // namespace android diff --git a/libs/nativedisplay/include/android/choreographer.h b/libs/nativedisplay/include/android/choreographer.h deleted file mode 100644 index 5fd3de9f3c..0000000000 --- a/libs/nativedisplay/include/android/choreographer.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @addtogroup Choreographer - * @{ - */ - -/** - * @file choreographer.h - */ - -#ifndef ANDROID_CHOREOGRAPHER_H -#define ANDROID_CHOREOGRAPHER_H - -#include -#include - -__BEGIN_DECLS - -struct AChoreographer; -typedef struct AChoreographer AChoreographer; - -/** - * Prototype of the function that is called when a new frame is being rendered. - * It's passed the time that the frame is being rendered as nanoseconds in the - * CLOCK_MONOTONIC time base, as well as the data pointer provided by the - * application that registered a callback. All callbacks that run as part of - * rendering a frame will observe the same frame time, so it should be used - * whenever events need to be synchronized (e.g. animations). - */ -typedef void (*AChoreographer_frameCallback)(long frameTimeNanos, void* data); - -/** - * Prototype of the function that is called when a new frame is being rendered. - * It's passed the time that the frame is being rendered as nanoseconds in the - * CLOCK_MONOTONIC time base, as well as the data pointer provided by the - * application that registered a callback. All callbacks that run as part of - * rendering a frame will observe the same frame time, so it should be used - * whenever events need to be synchronized (e.g. animations). - */ -typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data); - -/** - * Prototype of the function that is called when the display refresh rate - * changes. It's passed the new vsync period in nanoseconds, as well as the data - * pointer provided by the application that registered a callback. - */ -typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data); - -#if __ANDROID_API__ >= 24 - -/** - * Get the AChoreographer instance for the current thread. This must be called - * on an ALooper thread. - * - * Available since API level 24. - */ -AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24); - -/** - * Deprecated: Use AChoreographer_postFrameCallback64 instead. - */ -void AChoreographer_postFrameCallback(AChoreographer* choreographer, - AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24) __DEPRECATED_IN(29); - -/** - * Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead. - */ -void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer, - AChoreographer_frameCallback callback, void* data, - long delayMillis) __INTRODUCED_IN(24) __DEPRECATED_IN(29); - -#endif /* __ANDROID_API__ >= 24 */ - -#if __ANDROID_API__ >= 29 - -/** - * Power a callback to be run on the next frame. The data pointer provided will - * be passed to the callback function when it's called. - * - * Available since API level 29. - */ -void AChoreographer_postFrameCallback64(AChoreographer* choreographer, - AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29); - -/** - * Post a callback to be run on the frame following the specified delay. The - * data pointer provided will be passed to the callback function when it's - * called. - * - * Available since API level 29. - */ -void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer, - AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) __INTRODUCED_IN(29); - -#endif /* __ANDROID_API__ >= 29 */ - -#if __ANDROID_API__ >= 30 - -/** - * Registers a callback to be run when the display refresh rate changes. The - * data pointer provided will be passed to the callback function when it's - * called. The same callback may be registered multiple times, provided that a - * different data pointer is provided each time. - * - * If an application registers a callback for this choreographer instance when - * no new callbacks were previously registered, that callback is guaranteed to - * be dispatched. However, if the callback and associated data pointer are - * unregistered prior to running the callback, then the callback may be silently - * dropped. - * - * This api is thread-safe. Any thread is allowed to register a new refresh - * rate callback for the choreographer instance. - */ -void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer, - AChoreographer_refreshRateCallback, void* data); - -/** - * Unregisters a callback to be run when the display refresh rate changes, along - * with the data pointer previously provided when registering the callback. The - * callback is only unregistered when the data pointer matches one that was - * previously registered. - * - * This api is thread-safe. Any thread is allowed to unregister an existing - * refresh rate callback for the choreographer instance. When a refresh rate - * callback and associated data pointer are unregistered, then there is a - * guarantee that when the unregistration completes that that callback will not - * be run with the data pointer passed. - */ -void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer, - AChoreographer_refreshRateCallback, void* data); -#endif /* __ANDROID_API__ >= 30 */ - -__END_DECLS - -#endif // ANDROID_CHOREOGRAPHER_H - -/** @} */ diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h index 6a94a771e8..e2d036bfb0 100644 --- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h +++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h @@ -19,7 +19,7 @@ #include #include - +#include #include // This file provides a facade API on top of SurfaceTexture, which avoids using @@ -30,6 +30,20 @@ struct ASurfaceTexture; namespace android { +// Trampoline functions allowing libandroid.so to define the NDK symbols without including +// the entirety of libnativedisplay as a whole static lib. As libnativedisplay +// maintains global state, libnativedisplay can never be directly statically +// linked so that global state won't be duplicated. This way libandroid.so can +// reroute the NDK methods into the implementations defined by libnativedisplay +ANativeWindow* ASurfaceTexture_routeAcquireANativeWindow(ASurfaceTexture* st); +int ASurfaceTexture_routeAttachToGLContext(ASurfaceTexture* st, uint32_t texName); +int ASurfaceTexture_routeDetachFromGLContext(ASurfaceTexture* st); +void ASurfaceTexture_routeRelease(ASurfaceTexture* st); +int ASurfaceTexture_routeUpdateTexImage(ASurfaceTexture* st); +void ASurfaceTexture_routeGetTransformMatrix(ASurfaceTexture* st, float mtx[16]); +int64_t ASurfaceTexture_routeGetTimestamp(ASurfaceTexture* st); +ASurfaceTexture* ASurfaceTexture_routeFromSurfaceTexture(JNIEnv* env, jobject surfacetexture); + /** * ASurfaceTexture_getCurrentTextureTarget returns the texture target of the * current texture. diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt index 483fb25cb7..fc59431d08 100644 --- a/libs/nativedisplay/libnativedisplay.map.txt +++ b/libs/nativedisplay/libnativedisplay.map.txt @@ -20,6 +20,15 @@ LIBNATIVEDISPLAY { LIBNATIVEDISPLAY_PLATFORM { global: extern "C++" { + android::AChoreographer_initJVM*; + android::AChoreographer_routeGetInstance*; + android::AChoreographer_routePostFrameCallback*; + android::AChoreographer_routePostFrameCallbackDelayed*; + android::AChoreographer_routePostFrameCallback64*; + android::AChoreographer_routePostFrameCallbackDelayed64*; + android::AChoreographer_routeRegisterRefreshRateCallback*; + android::AChoreographer_routeUnregisterRefreshRateCallback*; + android::AChoreographer_signalRefreshRateCallbacks*; android::ADisplay_acquirePhysicalDisplays*; android::ADisplay_release*; android::ADisplay_getMaxSupportedFps*; @@ -36,6 +45,14 @@ LIBNATIVEDISPLAY_PLATFORM { android::ASurfaceTexture_takeConsumerOwnership*; android::ASurfaceTexture_releaseConsumerOwnership*; android::ASurfaceTexture_dequeueBuffer*; + android::ASurfaceTexture_routeAcquireANativeWindow*; + android::ASurfaceTexture_routeAttachToGLContext*; + android::ASurfaceTexture_routeDetachFromGLContext*; + android::ASurfaceTexture_routeGetTimestamp*; + android::ASurfaceTexture_routeGetTransformMatrix*; + android::ASurfaceTexture_routeUpdateTexImage*; + android::ASurfaceTexture_routeFromSurfaceTexture*; + android::ASurfaceTexture_routeRelease*; android::SurfaceTexture*; }; ASurfaceTexture_acquireANativeWindow; diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp index 1670fbba57..d1bcd8d1b1 100644 --- a/libs/nativedisplay/surfacetexture/surface_texture.cpp +++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp @@ -149,6 +149,37 @@ int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) { // The following functions are private/unstable API. namespace android { +ANativeWindow* ASurfaceTexture_routeAcquireANativeWindow(ASurfaceTexture* st) { + return ASurfaceTexture_acquireANativeWindow(st); +} + +int ASurfaceTexture_routeAttachToGLContext(ASurfaceTexture* st, uint32_t texName) { + return ASurfaceTexture_attachToGLContext(st, texName); +} + +void ASurfaceTexture_routeRelease(ASurfaceTexture* st) { + return ASurfaceTexture_release(st); +} + +int ASurfaceTexture_routeDetachFromGLContext(ASurfaceTexture* st) { + return ASurfaceTexture_detachFromGLContext(st); +} + +int ASurfaceTexture_routeUpdateTexImage(ASurfaceTexture* st) { + return ASurfaceTexture_updateTexImage(st); +} + +void ASurfaceTexture_routeGetTransformMatrix(ASurfaceTexture* st, float mtx[16]) { + return ASurfaceTexture_getTransformMatrix(st, mtx); +} + +int64_t ASurfaceTexture_routeGetTimestamp(ASurfaceTexture* st) { + return ASurfaceTexture_getTimestamp(st); +} + +ASurfaceTexture* ASurfaceTexture_routeFromSurfaceTexture(JNIEnv* env, jobject surfacetexture) { + return ASurfaceTexture_fromSurfaceTexture(env, surfacetexture); +} unsigned int ASurfaceTexture_getCurrentTextureTarget(ASurfaceTexture* st) { return st->consumer->getCurrentTextureTarget(); diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 5dedb6a1e7..cee36a121f 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -152,16 +152,9 @@ void EventThreadConnection::requestNextVsync() { mEventThread->requestNextVsync(this); } -void EventThreadConnection::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) { - ATRACE_NAME("enableConfigEvents"); - mConfigChanged = configChangeFlag; - - // In principle it's possible for rapidly toggling config events to drop an - // event here, but it's unlikely in practice. - if (configChangeFlag == ISurfaceComposer::eConfigChangedDispatch) { - mForcedConfigChangeDispatch = true; - mEventThread->requestLatestConfig(); - } +void EventThreadConnection::requestLatestConfig() { + ATRACE_NAME("requestLatestConfig"); + mEventThread->requestLatestConfig(this); } status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) { @@ -276,8 +269,12 @@ void EventThread::requestNextVsync(const sp& connection) } } -void EventThread::requestLatestConfig() { +void EventThread::requestLatestConfig(const sp& connection) { std::lock_guard lock(mMutex); + if (connection->mForcedConfigChangeDispatch) { + return; + } + connection->mForcedConfigChangeDispatch = true; auto pendingConfigChange = std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents), [&](const DisplayEventReceiver::Event& event) { @@ -384,6 +381,10 @@ void EventThread::threadMain(std::unique_lock& lock) { vsyncRequested |= connection->vsyncRequest != VSyncRequest::None; if (event && shouldConsumeEvent(*event, connection)) { + if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED && + connection->mForcedConfigChangeDispatch) { + connection->mForcedConfigChangeDispatch = false; + } consumers.push_back(connection); } @@ -459,8 +460,8 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, return true; case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: { - const bool forcedDispatch = connection->mForcedConfigChangeDispatch.exchange(false); - return forcedDispatch || + const bool oneTimeDispatch = connection->mForcedConfigChangeDispatch; + return oneTimeDispatch || connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch; } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 9e7086eb0c..64acbd72d0 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -81,19 +81,19 @@ public: status_t stealReceiveChannel(gui::BitTube* outChannel) override; status_t setVsyncRate(uint32_t rate) override; void requestNextVsync() override; // asynchronous - void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override; + void requestLatestConfig() override; // asynchronous // Called in response to requestNextVsync. const ResyncCallback resyncCallback; VSyncRequest vsyncRequest = VSyncRequest::None; - std::atomic mConfigChanged = + ISurfaceComposer::ConfigChanged mConfigChanged = ISurfaceComposer::ConfigChanged::eConfigChangedSuppress; // Store whether we need to force dispatching a config change separately - // if mConfigChanged ever changes before the config change is dispatched // then we still need to propagate an initial config to the app if we // haven't already. - std::atomic mForcedConfigChangeDispatch = false; + bool mForcedConfigChangeDispatch = false; private: virtual void onFirstRef(); @@ -129,11 +129,10 @@ public: virtual void setVsyncRate(uint32_t rate, const sp& connection) = 0; // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer. virtual void requestNextVsync(const sp& connection) = 0; - // Dispatches the most recent configuration // Usage of this method assumes that only the primary internal display // supports multiple display configurations. - virtual void requestLatestConfig() = 0; + virtual void requestLatestConfig(const sp& connection) = 0; // Retrieves the number of event connections tracked by this EventThread. virtual size_t getEventThreadConnectionCount() = 0; @@ -154,7 +153,7 @@ public: status_t registerDisplayEventConnection(const sp& connection) override; void setVsyncRate(uint32_t rate, const sp& connection) override; void requestNextVsync(const sp& connection) override; - void requestLatestConfig() override; + void requestLatestConfig(const sp& connection) override; // called before the screen is turned off from main thread void onScreenReleased() override; diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 50eb390471..054aaf8ae1 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -40,7 +40,7 @@ public: status_t(const sp &)); MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp &)); MOCK_METHOD1(requestNextVsync, void(const sp &)); - MOCK_METHOD0(requestLatestConfig, void()); + MOCK_METHOD1(requestLatestConfig, void(const sp &)); MOCK_METHOD1(pauseVsyncCallback, void(bool)); MOCK_METHOD0(getEventThreadConnectionCount, size_t()); }; -- cgit v1.2.3-59-g8ed1b From f9f3de2434d82942b989621c43490eff46b8512d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 6 May 2020 17:14:39 -0700 Subject: binder tests respect libbinder bitness Some 32-bit kernels use a binder kernel interface with a different API controlled by the kernel configuration CONFIG_ANDROID_BINDER_IPC_32BIT. This changes builds versions of these tests built for this bitness specially so that they can run and work on these devices. Test: atest --all binderLibTest{,_IPC_32} binderDriverInterfaceTest{,_IPC_32} Bug: 154755898 Change-Id: I82b47e8064564a037bf8ed453e9ae7b8901b5667 --- libs/binder/tests/Android.bp | 5 +++ libs/binder/tests/binderAbiHelper.h | 52 +++++++++++++++++++++++++ libs/binder/tests/binderDriverInterfaceTest.cpp | 3 ++ libs/binder/tests/binderLibTest.cpp | 4 ++ 4 files changed, 64 insertions(+) create mode 100644 libs/binder/tests/binderAbiHelper.h (limited to 'libs') diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 69fdd7c5d8..c0da2cd8d4 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -27,7 +27,9 @@ cc_test { defaults: ["binder_test_defaults"], srcs: ["binderDriverInterfaceTest.cpp"], compile_multilib: "32", + multilib: { lib32: { suffix: "" } }, cflags: ["-DBINDER_IPC_32BIT=1"], + test_suites: ["vts"], } cc_test { @@ -52,7 +54,10 @@ cc_test { "libutils", ], compile_multilib: "32", + multilib: { lib32: { suffix: "" } }, cflags: ["-DBINDER_IPC_32BIT=1"], + test_suites: ["vts"], + require_root: true, } cc_test { diff --git a/libs/binder/tests/binderAbiHelper.h b/libs/binder/tests/binderAbiHelper.h new file mode 100644 index 0000000000..369b55dc22 --- /dev/null +++ b/libs/binder/tests/binderAbiHelper.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#ifdef BINDER_IPC_32BIT +static constexpr bool kBuild32Abi = true; +#else +static constexpr bool kBuild32Abi = false; +#endif + +// TODO: remove when CONFIG_ANDROID_BINDER_IPC_32BIT is no longer supported +static inline bool ReadKernelConfigIs32BitAbi() { + // failure case implies we run with standard ABI + return 0 == system("zcat /proc/config.gz | grep -E \"^CONFIG_ANDROID_BINDER_IPC_32BIT=y$\""); +} + +static inline void ExitIfWrongAbi() { + bool runtime32Abi = ReadKernelConfigIs32BitAbi(); + + if (kBuild32Abi != runtime32Abi) { + std::cout << "[==========] Running 1 test from 1 test suite." << std::endl; + std::cout << "[----------] Global test environment set-up." << std::endl; + std::cout << "[----------] 1 tests from BinderLibTest" << std::endl; + std::cout << "[ RUN ] BinderTest.AbortForWrongAbi" << std::endl; + std::cout << "[ INFO ] test build abi 32: " << kBuild32Abi << " runtime abi 32: " << runtime32Abi << " so, skipping tests " << std::endl; + std::cout << "[ OK ] BinderTest.AbortForWrongAbi (0 ms) " << std::endl; + std::cout << "[----------] 1 tests from BinderTest (0 ms total)" << std::endl; + std::cout << "" << std::endl; + std::cout << "[----------] Global test environment tear-down" << std::endl; + std::cout << "[==========] 1 test from 1 test suite ran. (0 ms total)" << std::endl; + std::cout << "[ PASSED ] 1 tests." << std::endl; + exit(0); + } +} + diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp index f3ed6a613c..8cc3054f80 100644 --- a/libs/binder/tests/binderDriverInterfaceTest.cpp +++ b/libs/binder/tests/binderDriverInterfaceTest.cpp @@ -25,6 +25,8 @@ #include #include +#include "binderAbiHelper.h" + #define BINDER_DEV_NAME "/dev/binder" testing::Environment* binder_env; @@ -361,6 +363,7 @@ TEST_F(BinderDriverInterfaceTest, RequestDeathNotification) { } int main(int argc, char **argv) { + ExitIfWrongAbi(); ::testing::InitGoogleTest(&argc, argv); binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv()); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index e343df7e50..40de2db2cb 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -32,6 +32,8 @@ #include #include +#include "binderAbiHelper.h" + #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) using namespace android; @@ -1451,6 +1453,8 @@ int run_server(int index, int readypipefd, bool usePoll) } int main(int argc, char **argv) { + ExitIfWrongAbi(); + if (argc == 4 && !strcmp(argv[1], "--servername")) { binderservername = argv[2]; } else { -- cgit v1.2.3-59-g8ed1b From 6213bd900145b9189c7d87aec8a2714a66c8d057 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 8 May 2020 17:42:25 -0700 Subject: Provide a fixed transform hint if the layer is in a fixed orientation 1/2 The transform hint is used to prevent allocating a buffer of a different size when a layer is rotated. The producer can choose to consume the hint and allocate the buffer with the same size. Provide the graphic producer a transform hint if the layer and its children are in an orientation different from the display's orientation. The caller is responsible for clearing this transform hint if the layer is no longer in a fixed orientation. Bug: 152919661 Test: atest VulkanPreTransformTest Test: confirm with winscope trace, buffers are allocated taking into account the transform hint in fixed orientation scenarios Test: go/wm-smoke Change-Id: Iea9dcf909921802a5be5c44dd61be3274f36bbd8 --- libs/gui/LayerState.cpp | 6 +++++ libs/gui/SurfaceComposerClient.cpp | 16 ++++++++++++++ libs/gui/include/gui/LayerState.h | 14 +++++++++++- libs/gui/include/gui/SurfaceComposerClient.h | 8 +++++++ services/surfaceflinger/BufferLayer.cpp | 7 ++++++ services/surfaceflinger/BufferLayer.h | 8 +++++++ services/surfaceflinger/BufferQueueLayer.cpp | 9 +++----- services/surfaceflinger/BufferQueueLayer.h | 2 +- services/surfaceflinger/BufferStateLayer.cpp | 7 ------ services/surfaceflinger/BufferStateLayer.h | 4 ---- services/surfaceflinger/Layer.cpp | 33 +++++++++++++++++++++++----- services/surfaceflinger/Layer.h | 20 ++++++++++++++++- services/surfaceflinger/SurfaceFlinger.cpp | 33 ++++++++++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 7 +++--- 14 files changed, 134 insertions(+), 40 deletions(-) (limited to 'libs') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index f7158d0472..e43446ac8c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -116,6 +116,7 @@ status_t layer_state_t::write(Parcel& output) const output.writeInt32(frameRateSelectionPriority); output.writeFloat(frameRate); output.writeByte(frameRateCompatibility); + output.writeUint32(fixedTransformHint); return NO_ERROR; } @@ -198,6 +199,7 @@ status_t layer_state_t::read(const Parcel& input) frameRateSelectionPriority = input.readInt32(); frameRate = input.readFloat(); frameRateCompatibility = input.readByte(); + fixedTransformHint = static_cast(input.readUint32()); return NO_ERROR; } @@ -433,6 +435,10 @@ void layer_state_t::merge(const layer_state_t& other) { frameRate = other.frameRate; frameRateCompatibility = other.frameRateCompatibility; } + if (other.what & eFixedTransformHintChanged) { + what |= eFixedTransformHintChanged; + fixedTransformHint = other.fixedTransformHint; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a52f298e77..5922f3a876 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1437,6 +1437,22 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( + const sp& sc, int32_t fixedTransformHint) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + const ui::Transform::RotationFlags transform = fixedTransformHint == -1 + ? ui::Transform::ROT_INVALID + : ui::Transform::toRotationFlags(static_cast(fixedTransformHint)); + s->what |= layer_state_t::eFixedTransformHintChanged; + s->fixedTransformHint = transform; + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 2b2f7735ba..e60f6777ae 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -35,6 +35,7 @@ #include #include #include +#include #include namespace android { @@ -103,6 +104,7 @@ struct layer_state_t { eFrameRateChanged = 0x40'00000000, eBackgroundBlurRadiusChanged = 0x80'00000000, eProducerDisconnect = 0x100'00000000, + eFixedTransformHintChanged = 0x200'00000000, }; layer_state_t() @@ -136,7 +138,8 @@ struct layer_state_t { shadowRadius(0.0f), frameRateSelectionPriority(-1), frameRate(0.0f), - frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) { + frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + fixedTransformHint(ui::Transform::ROT_INVALID) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -225,6 +228,15 @@ struct layer_state_t { // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; int8_t frameRateCompatibility; + + // Set by window manager indicating the layer and all its children are + // in a different orientation than the display. The hint suggests that + // the graphic producers should receive a transform hint as if the + // display was in this orientation. When the display changes to match + // the layer orientation, the graphic producer may not need to allocate + // a buffer of a different size. -1 means the transform hint is not set, + // otherwise the value will be a valid ui::Rotation. + ui::Transform::RotationFlags fixedTransformHint; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 531aed7ac4..e981a39edc 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -519,6 +519,14 @@ public: Transaction& setFrameRate(const sp& sc, float frameRate, int8_t compatibility); + // Set by window manager indicating the layer and all its children are + // in a different orientation than the display. The hint suggests that + // the graphic producers should receive a transform hint as if the + // display was in this orientation. When the display changes to match + // the layer orientation, the graphic producer may not need to allocate + // a buffer of a different size. + Transaction& setFixedTransformHint(const sp& sc, int32_t transformHint); + status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 5b28384c08..8ecdd95cca 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -843,6 +843,13 @@ void BufferLayer::updateCloneBufferInfo() { mDrawingState.inputInfo = tmpInputInfo; } +void BufferLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) const { + mTransformHint = getFixedTransformHint(); + if (mTransformHint == ui::Transform::ROT_INVALID) { + mTransformHint = displayTransformHint; + } +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 56bab1bbbe..cfccc8ab79 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -117,6 +117,10 @@ public: sp getBuffer() const override; + ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; } + + void setTransformHint(ui::Transform::RotationFlags displayTransformHint) const override; + // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- @@ -205,6 +209,10 @@ protected: virtual uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; + // Transform hint provided to the producer. This must be accessed holding + /// the mStateLock. + mutable ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; + private: // Returns true if this layer requires filtering bool needsFiltering(const sp& displayDevice) const override; diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index f4e630e4d8..5d807681b2 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -58,8 +58,9 @@ void BufferQueueLayer::onLayerDisplayed(const sp& releaseFence) { } } -void BufferQueueLayer::setTransformHint(uint32_t orientation) const { - mConsumer->setTransformHint(orientation); +void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) const { + BufferLayer::setTransformHint(displayTransformHint); + mConsumer->setTransformHint(mTransformHint); } std::vector BufferQueueLayer::getOccupancyHistory(bool forceFlush) { @@ -493,10 +494,6 @@ void BufferQueueLayer::onFirstRef() { if (!mFlinger->isLayerTripleBufferingDisabled()) { mProducer->setMaxDequeuedBufferCount(2); } - - if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) { - updateTransformHint(display); - } } status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) { diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 16b4b6e25c..9bcb63aca2 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -43,7 +43,7 @@ public: void onLayerDisplayed(const sp& releaseFence) override; - void setTransformHint(uint32_t orientation) const override; + void setTransformHint(ui::Transform::RotationFlags displayTransformHint) const override; std::vector getOccupancyHistory(bool forceFlush) override; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index a121ce0672..a1ed6d7116 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -51,9 +51,6 @@ BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) { mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; mCurrentState.dataspace = ui::Dataspace::V0_SRGB; - if (const auto display = args.displayDevice) { - updateTransformHint(display); - } } BufferStateLayer::~BufferStateLayer() { @@ -108,10 +105,6 @@ void BufferStateLayer::onLayerDisplayed(const sp& releaseFence) { } } -void BufferStateLayer::setTransformHint(uint32_t orientation) const { - mTransformHint = orientation; -} - void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->transformHint = mTransformHint; diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 5873a7314f..00fa7f7a2d 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -42,7 +42,6 @@ public: const char* getType() const override { return "BufferStateLayer"; } void onLayerDisplayed(const sp& releaseFence) override; - void setTransformHint(uint32_t orientation) const override; void releasePendingBuffer(nsecs_t dequeueReadyTime) override; void finalizeFrameEventHistory(const std::shared_ptr& glDoneFence, @@ -68,7 +67,6 @@ public: } Rect getCrop(const Layer::State& s) const; - uint32_t getTransformHint() const { return mTransformHint; } bool setTransform(uint32_t transform) override; bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; @@ -164,8 +162,6 @@ private: bool mReleasePreviousBuffer = false; nsecs_t mCallbackHandleAcquireTime = -1; - mutable uint32_t mTransformHint = 0; - // TODO(marissaw): support sticky transform for LEGACY camera mode class HwcSlotGenerator : public ClientCache::ErasedRecipient { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 752407aedc..25929ed1d7 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -117,6 +117,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.metadata = args.metadata; mCurrentState.shadowRadius = 0.f; mCurrentState.treeHasFrameRateVote = false; + mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID; // drawing state & current state are identical mDrawingState = mCurrentState; @@ -1333,6 +1334,18 @@ bool Layer::setShadowRadius(float shadowRadius) { return true; } +bool Layer::setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint) { + if (mCurrentState.fixedTransformHint == fixedTransformHint) { + return false; + } + + mCurrentState.sequence++; + mCurrentState.fixedTransformHint = fixedTransformHint; + mCurrentState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + void Layer::updateTreeHasFrameRateVote() { const auto traverseTree = [&](const LayerVector::Visitor& visitor) { auto parent = getParent(); @@ -1460,19 +1473,19 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const { } void Layer::updateTransformHint(const sp& display) const { - uint32_t orientation = 0; + ui::Transform::RotationFlags transformHint = ui::Transform::ROT_0; // Disable setting transform hint if the debug flag is set. if (!mFlinger->mDebugDisableTransformHint) { // The transform hint is used to improve performance, but we can // only have a single transform hint, it cannot // apply to all displays. const ui::Transform& planeTransform = display->getTransform(); - orientation = planeTransform.getOrientation(); - if (orientation & ui::Transform::ROT_INVALID) { - orientation = 0; + transformHint = static_cast(planeTransform.getOrientation()); + if (transformHint & ui::Transform::ROT_INVALID) { + transformHint = ui::Transform::ROT_0; } } - setTransformHint(orientation); + setTransformHint(transformHint); } // ---------------------------------------------------------------------------- @@ -2076,6 +2089,16 @@ half Layer::getAlpha() const { return parentAlpha * getDrawingState().color.a; } +ui::Transform::RotationFlags Layer::getFixedTransformHint() const { + ui::Transform::RotationFlags fixedTransformHint = mCurrentState.fixedTransformHint; + if (fixedTransformHint != ui::Transform::ROT_INVALID) { + return fixedTransformHint; + } + const auto& p = mCurrentParent.promote(); + if (!p) return fixedTransformHint; + return p->getFixedTransformHint(); +} + half4 Layer::getColor() const { const half4 color(getDrawingState().color); return half4(color.r, color.g, color.b, getAlpha()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b6303335cb..224ea19ffb 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -262,6 +262,15 @@ public: // Indicates whether parents / children of this layer had set FrameRate bool treeHasFrameRateVote; + + // Set by window manager indicating the layer and all its children are + // in a different orientation than the display. The hint suggests that + // the graphic producers should receive a transform hint as if the + // display was in this orientation. When the display changes to match + // the layer orientation, the graphic producer may not need to allocate + // a buffer of a different size. ui::Transform::ROT_INVALID means the + // a fixed transform hint is not set. + ui::Transform::RotationFlags fixedTransformHint; }; explicit Layer(const LayerCreationArgs& args); @@ -388,6 +397,7 @@ public: virtual bool setColorSpaceAgnostic(const bool agnostic); bool setShadowRadius(float shadowRadius); virtual bool setFrameRateSelectionPriority(int32_t priority); + virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; @@ -611,7 +621,7 @@ public: bool getClearClientTarget(const sp& display) const; virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; } - virtual void setTransformHint(uint32_t /*orientation*/) const { } + virtual void setTransformHint(ui::Transform::RotationFlags /*transformHint*/) const {} /* * called after composition. @@ -689,6 +699,8 @@ public: virtual sp getBuffer() const { return nullptr; } + virtual ui::Transform::RotationFlags getTransformHint() const { return ui::Transform::ROT_0; } + /* * Returns if a frame is ready */ @@ -733,6 +745,12 @@ public: int32_t getBackgroundBlurRadius() const; bool drawShadows() const { return mEffectiveShadowRadius > 0.f; }; + // Returns the transform hint set by Window Manager on the layer or one of its parents. + // This traverses the current state because the data is needed when creating + // the layer(off drawing thread) and the hint should be available before the producer + // is ready to acquire a buffer. + ui::Transform::RotationFlags getFixedTransformHint() const; + // Returns how rounded corners should be drawn for this layer. // This will traverse the hierarchy until it reaches its root, finding topmost rounded // corner definition and converting it into current layer's coordinates. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4ca2074ad5..a2e9e2f6da 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2764,7 +2764,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) processDisplayHotplugEventsLocked(); } - if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) { + if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) { // The transform hint might have changed for some layers // (either because a display has changed, or because a layer // as changed). @@ -2832,7 +2832,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) }); } - /* * Perform our own transaction if needed */ @@ -3137,7 +3136,8 @@ void SurfaceFlinger::invalidateHwcGeometry() status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, const sp& parentHandle, - const sp& parentLayer, bool addToCurrentState) { + const sp& parentLayer, bool addToCurrentState, + uint32_t* outTransformHint) { // add this layer to the current state list { Mutex::Autolock _l(mStateLock); @@ -3178,6 +3178,14 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const spupdateTransformHint(display); + } + if (outTransformHint) { + *outTransformHint = lbc->getTransformHint(); + } + mLayersAdded = true; } @@ -3679,7 +3687,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( mCurrentState.layersSortedByZ.add(layer); // we need traversal (state changed) // AND transaction (list changed) - flags |= eTransactionNeeded|eTraversalNeeded|eDisplayLayerStackChanged; + flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded; } } if (what & layer_state_t::eDeferTransaction_legacy) { @@ -3776,6 +3784,11 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + if (what & layer_state_t::eFixedTransformHintChanged) { + if (layer->setFixedTransformHint(s.fixedTransformHint)) { + flags |= eTraversalNeeded | eTransformHintUpdateNeeded; + } + } // This has to happen after we reparent children because when we reparent to null we remove // child layers from current state and remove its relative z. If the children are reparented in // the same transaction, then we have to make sure we reparent the children first so we do not @@ -3863,7 +3876,8 @@ status_t SurfaceFlinger::mirrorLayer(const sp& client, const sp mirrorLayer->mClonedChild = mirrorFrom->createClone(); } - return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false); + return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false, + nullptr /* outTransformHint */); } status_t SurfaceFlinger::createLayer(const String8& name, const sp& client, uint32_t w, @@ -3908,7 +3922,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie break; case ISurfaceComposerClient::eFXSurfaceBufferState: result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags, - std::move(metadata), handle, outTransformHint, &layer); + std::move(metadata), handle, &layer); break; case ISurfaceComposerClient::eFXSurfaceEffect: // check if buffer size is set for color layer. @@ -3946,7 +3960,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp& clie bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess(); result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, - addToCurrentState); + addToCurrentState, outTransformHint); if (result != NO_ERROR) { return result; } @@ -4023,14 +4037,11 @@ status_t SurfaceFlinger::createBufferQueueLayer(const sp& client, std::s status_t SurfaceFlinger::createBufferStateLayer(const sp& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, sp* handle, - uint32_t* outTransformHint, sp* outLayer) { + sp* outLayer) { LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata)); args.displayDevice = getDefaultDisplayDevice(); args.textureName = getNewTexture(); sp layer = getFactory().createBufferStateLayer(args); - if (outTransformHint) { - *outTransformHint = layer->getTransformHint(); - } *handle = layer->getHandle(); *outLayer = layer; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f3984ed8d4..7a51328e6c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -117,7 +117,7 @@ enum { eTransactionNeeded = 0x01, eTraversalNeeded = 0x02, eDisplayTransactionNeeded = 0x04, - eDisplayLayerStackChanged = 0x08, + eTransformHintUpdateNeeded = 0x08, eTransactionFlushNeeded = 0x10, eTransactionMask = 0x1f, }; @@ -675,8 +675,7 @@ private: status_t createBufferStateLayer(const sp& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, - sp* outHandle, uint32_t* outTransformHint, - sp* outLayer); + sp* outHandle, sp* outLayer); status_t createEffectLayer(const sp& client, std::string name, uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata, sp* outHandle, @@ -701,7 +700,7 @@ private: status_t addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, const sp& parentHandle, const sp& parentLayer, - bool addToCurrentState); + bool addToCurrentState, uint32_t* outTransformHint); // Traverse through all the layers and compute and cache its bounds. void computeLayerBounds(); -- cgit v1.2.3-59-g8ed1b From 7bcb89317d296296c67b6da2d5a27ecebd9afe19 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 16 Apr 2020 18:48:32 +0900 Subject: Set min_sdk_version to be part of mainline modules Modules contributing mainline modules (APK/APEX) should set min_sdk_version as well as apex_available. For now setting min_sdk_version doesn't change build outputs. But build-time checks will be added soon. Exempt-From-Owner-Approval: cherry-pick from aosp Bug: 152655956 Test: m Merged-In: Ifea5ed988fad2e0d29271e6e9cbf0e12100b37d9 Change-Id: Ifea5ed988fad2e0d29271e6e9cbf0e12100b37d9 (cherry picked from commit a395c8d9aa8e985d8c45f5dffa6518550a70d9a1) --- headers/Android.bp | 1 + libs/arect/Android.bp | 1 + libs/binder/Android.bp | 2 ++ libs/binderthreadstate/Android.bp | 3 ++- libs/gui/Android.bp | 1 + libs/gui/sysprop/Android.bp | 3 +++ libs/nativebase/Android.bp | 3 ++- libs/nativewindow/Android.bp | 1 + libs/ui/Android.bp | 2 ++ libs/vr/libpdx/Android.bp | 1 + 10 files changed, 16 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/headers/Android.bp b/headers/Android.bp index 82bc8a15f7..53372357e6 100644 --- a/headers/Android.bp +++ b/headers/Android.bp @@ -17,4 +17,5 @@ cc_library_headers { "libutils_headers", "libstagefright_foundation_headers", ], + min_sdk_version: "29", } diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 2518b1427d..f66673f6ad 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -35,4 +35,5 @@ cc_library_static { enabled: true, }, }, + min_sdk_version: "29", } diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 72982824f4..db4aba8640 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -28,6 +28,7 @@ cc_library_headers { "libcutils_headers", "libutils_headers", ], + min_sdk_version: "29", } // These interfaces are android-specific implementation unrelated to binder @@ -152,6 +153,7 @@ cc_library { sanitize: { misc_undefined: ["integer"], }, + min_sdk_version: "29", } // AIDL interface between libbinder and framework.jar diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp index 5eb509c4a0..88752ee87e 100644 --- a/libs/binderthreadstate/Android.bp +++ b/libs/binderthreadstate/Android.bp @@ -22,7 +22,7 @@ cc_library_static { shared_libs: [ "libbinder", - "libhidlbase", // libhwbinder is in here + "libhidlbase", // libhwbinder is in here ], export_include_dirs: ["include"], @@ -31,6 +31,7 @@ cc_library_static { "-Wall", "-Werror", ], + min_sdk_version: "29", } hidl_package_root { diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 7f57f5dd4e..7976ecb707 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -27,6 +27,7 @@ cc_library_headers { "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", ], + min_sdk_version: "29", } cc_library_shared { diff --git a/libs/gui/sysprop/Android.bp b/libs/gui/sysprop/Android.bp index e7f7c1fc86..64b1eacaa2 100644 --- a/libs/gui/sysprop/Android.bp +++ b/libs/gui/sysprop/Android.bp @@ -4,4 +4,7 @@ sysprop_library { api_packages: ["android.sysprop"], property_owner: "Platform", vendor_available: true, + cpp: { + min_sdk_version: "29", + }, } diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp index 7375a2bc2f..9e7e4a2291 100644 --- a/libs/nativebase/Android.bp +++ b/libs/nativebase/Android.bp @@ -25,5 +25,6 @@ cc_library_headers { windows: { enabled: true, }, - } + }, + min_sdk_version: "29", } diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index 5baec2f70f..ee006aaaba 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -25,6 +25,7 @@ cc_library_headers { name: "libnativewindow_headers", export_include_dirs: ["include"], vendor_available: true, + min_sdk_version: "29", } ndk_library { diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 458ee675d8..1ee8c7105c 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -133,6 +133,7 @@ cc_library_shared { "libhardware_headers", "libui_headers", ], + min_sdk_version: "29", } cc_library_headers { @@ -151,6 +152,7 @@ cc_library_headers { export_header_lib_headers: [ "libnativewindow_headers", ], + min_sdk_version: "29", } // defaults to enable VALIDATE_REGIONS traces diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp index 23a4224e05..24ba83048d 100644 --- a/libs/vr/libpdx/Android.bp +++ b/libs/vr/libpdx/Android.bp @@ -2,6 +2,7 @@ cc_library_headers { name: "libpdx_headers", export_include_dirs: ["private"], vendor_available: true, + min_sdk_version: "29", } cc_library_static { -- cgit v1.2.3-59-g8ed1b From b66d04b0a207046b59ae0b40a4c435c22e8786bf Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Mon, 11 May 2020 06:52:15 -0700 Subject: AChoreographer: Avoid potential NULL dereference We move our nullptr check to before our dereference of the pointer. Test: TreeHugger Bug: 154874011 Change-Id: If1e51b8fb88f72b6b4cbda52543bf093e6c76ca9 --- libs/nativedisplay/AChoreographer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index ea51245ac6..e458b2ecfb 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -250,12 +250,12 @@ void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallba } if (needsRegistration) { JNIEnv* env = getJniEnv(); - jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, - gJni.displayManagerGlobal.getInstance); if (env == nullptr) { - ALOGW("JNI environment is unavailable, skipping registeration"); + ALOGW("JNI environment is unavailable, skipping registration"); return; } + jobject dmg = env->CallStaticObjectMethod(gJni.displayManagerGlobal.clazz, + gJni.displayManagerGlobal.getInstance); if (dmg == nullptr) { ALOGW("DMS is not initialized yet: skipping registration"); return; -- cgit v1.2.3-59-g8ed1b From 54042e0ae4a5ea5e78733e7e6c4a9575a86c1415 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Wed, 13 May 2020 16:04:07 +0900 Subject: gui/math/gralloc: Set min_sdk_version Modules contributing mainline modules (APK/APEX) should set min_sdk_version as well as apex_available. For now setting min_sdk_version doesn't change build outputs. But build-time checks will be added soon. Bug: 152655956 Test: m Change-Id: Ib7685f5f4f924ac145eb4f10ad83a6c0548b2206 --- libs/gralloc/types/Android.bp | 5 +++++ libs/gui/Android.bp | 5 +++++ libs/math/Android.bp | 8 ++++++++ 3 files changed, 18 insertions(+) (limited to 'libs') diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp index 00f7484a80..66fb295a19 100644 --- a/libs/gralloc/types/Android.bp +++ b/libs/gralloc/types/Android.bp @@ -27,6 +27,11 @@ cc_library { enabled: true, support_system_process: true, }, + apex_available: [ + "//apex_available:platform", + "com.android.media.swcodec", + ], + min_sdk_version: "29", srcs: [ "Gralloc4.cpp" diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 7976ecb707..4a4510e047 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -130,6 +130,11 @@ cc_library_shared { cc_library_static { name: "libgui_bufferqueue_static", vendor_available: true, + apex_available: [ + "//apex_available:platform", + "com.android.media.swcodec", + ], + min_sdk_version: "29", cflags: [ "-DNO_BUFFERHUB", diff --git a/libs/math/Android.bp b/libs/math/Android.bp index 693bace1f4..3b1edcb43a 100644 --- a/libs/math/Android.bp +++ b/libs/math/Android.bp @@ -16,6 +16,14 @@ cc_library_static { name: "libmath", host_supported: true, vendor_available: true, + apex_available: [ + "//apex_available:platform", + "com.android.media", + "com.android.media.swcodec", + "com.android.neuralnetworks", + ], + min_sdk_version: "29", + export_include_dirs: ["include"], } -- cgit v1.2.3-59-g8ed1b From c5d0344511e6cc2ce5212e21c681a396aac6f9ff Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 13 May 2020 09:58:25 -0700 Subject: Make libbinder not available to media.swcodec apex media.swcodec no longer depends on libbinder. bug: 139201422 bug: 139016109 test: builds Change-Id: I633e733902d4d26c0a9249113b6cf4bdde0877ee --- libs/binder/Android.bp | 3 --- 1 file changed, 3 deletions(-) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index db4aba8640..2832bc91f4 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -74,9 +74,6 @@ cc_library { // or dessert updates. Instead, apex users should use libbinder_ndk. apex_available: [ "//apex_available:platform", - // TODO(b/139016109) remove these three - "com.android.media.swcodec", - "test_com.android.media.swcodec", ], srcs: [ -- cgit v1.2.3-59-g8ed1b From e5b112ae7cb970ad4837ecc03104ad8ad39f478c Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 13 May 2020 21:55:10 +0000 Subject: Revert "Make libbinder not available to media.swcodec apex" This reverts commit c5d0344511e6cc2ce5212e21c681a396aac6f9ff. Reason for revert: breaks ndk build on rvc-dev-plus-aosp, not sure why. https://android-build.googleplex.com/builds/submitted/6492183/ndk/latest/view/logs/build_error.log Change-Id: Ife18316c47a68a3d93c5a73eb47a142525dbbd0d bug: 156531370 --- libs/binder/Android.bp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 2832bc91f4..db4aba8640 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -74,6 +74,9 @@ cc_library { // or dessert updates. Instead, apex users should use libbinder_ndk. apex_available: [ "//apex_available:platform", + // TODO(b/139016109) remove these three + "com.android.media.swcodec", + "test_com.android.media.swcodec", ], srcs: [ -- cgit v1.2.3-59-g8ed1b From 6ab8a281afc60fbff0f1d6bbd052ddb2d26d4cc2 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 14 May 2020 02:31:06 +0000 Subject: Revert "Revert "Make libbinder not available to media.swcodec apex"" This reverts commit e5b112ae7cb970ad4837ecc03104ad8ad39f478c. Reason for revert: reland with fix bug: 139201422 bug: 139016109 Change-Id: I23f41fecef76c032f82296fec355294ae8530a56 --- libs/binder/Android.bp | 3 --- 1 file changed, 3 deletions(-) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index db4aba8640..2832bc91f4 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -74,9 +74,6 @@ cc_library { // or dessert updates. Instead, apex users should use libbinder_ndk. apex_available: [ "//apex_available:platform", - // TODO(b/139016109) remove these three - "com.android.media.swcodec", - "test_com.android.media.swcodec", ], srcs: [ -- cgit v1.2.3-59-g8ed1b From b5108191c34140478ef3a6cd06e04fad639dcb96 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Thu, 14 May 2020 16:01:10 -0700 Subject: Add null check for fgets in BufferQueueCore When compiling BufferQueueCore for host linux, the following warning/error occurs: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result] Add a simple null check to avoid this error. This is a no-op in terms of functionality. Bug: 156675939 Test: m -j libgui Change-Id: I460731ebaf0272fd5376f244e65b763da44e14f0 --- libs/gui/BufferQueueCore.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 8d80833ebe..5023b6bb81 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -75,10 +75,12 @@ static status_t getProcessName(int pid, String8& name) { if (NULL != fp) { const size_t size = 64; char proc_name[size]; - fgets(proc_name, size, fp); + char* result = fgets(proc_name, size, fp); fclose(fp); - name = proc_name; - return NO_ERROR; + if (result != nullptr) { + name = proc_name; + return NO_ERROR; + } } return INVALID_OPERATION; } -- cgit v1.2.3-59-g8ed1b From 4d360c65f54433b30c20c92c5c18dfab76ecfdf0 Mon Sep 17 00:00:00 2001 From: Adam Wright Date: Sat, 16 May 2020 10:33:19 +0000 Subject: Revert "Revert "Revert "Make libbinder not available to media.sw..." Revert submission 11485868-reland-libbinder Testing potential culprit for b/156778943 ("pthread_mutex_destroy called on a destroyed mutex" inside libstagefright). Reason for revert: broken above test Exempt-From-Owner-Approval: revert due to test breakage. Reverted Changes: I045836e10:Use NO_IMEMORY version of libstagefright_foundatio... I23f41fece:Revert "Revert "Make libbinder not available to me... bug: 156778943 Change-Id: Idfea55e47cd80dc80c58bfef20e7e274f944dcaf --- libs/binder/Android.bp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 2832bc91f4..db4aba8640 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -74,6 +74,9 @@ cc_library { // or dessert updates. Instead, apex users should use libbinder_ndk. apex_available: [ "//apex_available:platform", + // TODO(b/139016109) remove these three + "com.android.media.swcodec", + "test_com.android.media.swcodec", ], srcs: [ -- cgit v1.2.3-59-g8ed1b From 26476f3e0b57839b8952b0b1d90621bae8922e6f Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 15 May 2020 23:43:52 +0000 Subject: libbinder: do not destruct SM global Let linux clean it up, since this may be accessed by some threads after the main thread is destructed. Bug: 154507808 # longterm Bug: 156785633 Test: w/ repro which calls defaultServiceManager off main thread Change-Id: Ic109f4bdca3893e6b0b192ac27f3ff03ada6f9e2 (cherry picked from commit 1698ffd088b9c2e5e601a1c82352c54a338bca32) Merged-In: Ic109f4bdca3893e6b0b192ac27f3ff03ada6f9e2 --- libs/binder/IServiceManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 9888b59854..deaa15fa7c 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -85,8 +85,8 @@ private: sp mTheRealServiceManager; }; -static std::once_flag gSmOnce; -static sp gDefaultServiceManager; +[[clang::no_destroy]] static std::once_flag gSmOnce; +[[clang::no_destroy]] static sp gDefaultServiceManager; sp defaultServiceManager() { -- cgit v1.2.3-59-g8ed1b From 01097e2410e75f1883f4e48af6a7889bd8cda052 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Wed, 13 May 2020 17:24:09 +0900 Subject: setDefaultImpl aborts on a second call The actual problem is that default implementation is set globally. setDefaultImpl might not work as expected when it is called twice with different instances. Because we don't have a proper solution for the problem, we prevent calling setDefaultImpl() twice by aborting. Exempt-From-Owner-Approval: approved Bug: 140139809 Test: ./runtests.sh (in /system/tools/aidl) Merged-In: I659d3eaad3a45dcba608fa79a08f083f84bc4d58 Change-Id: I659d3eaad3a45dcba608fa79a08f083f84bc4d58 (cherry picked from commit 81087399e99984db8049d1b319522536bac6f557) --- libs/binder/include/binder/IInterface.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 3a401adfa5..7116154951 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -20,6 +20,8 @@ #include +#include + namespace android { // ---------------------------------------------------------------------- @@ -155,7 +157,11 @@ public: \ std::unique_ptr I##INTERFACE::default_impl; \ bool I##INTERFACE::setDefaultImpl(std::unique_ptr impl)\ { \ - if (!I##INTERFACE::default_impl && impl) { \ + /* Only one user of this interface can use this function */ \ + /* at a time. This is a heuristic to detect if two different */ \ + /* users in the same process use this function. */ \ + assert(!I##INTERFACE::default_impl); \ + if (impl) { \ I##INTERFACE::default_impl = std::move(impl); \ return true; \ } \ -- cgit v1.2.3-59-g8ed1b From fb10b6b588c21b209e1522b4867c6b40b4be047e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 19 May 2020 18:10:07 +0000 Subject: log when waiting on a servicemanager Since vndservicemanager is no longer installed by default, this gets hit on those devices. Fixes: 156571068 Test: TH Change-Id: I31af865326e9a69042e5c53b63637b95d6de9ad1 (cherry picked from commit 39a572183a83a327008e8e8b37c315230778ba05) Merged-In: I31af865326e9a69042e5c53b63637b95d6de9ad1 --- libs/binder/IServiceManager.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs') diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 9888b59854..912d4706ed 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -95,6 +95,7 @@ sp defaultServiceManager() while (sm == nullptr) { sm = interface_cast(ProcessState::self()->getContextObject(nullptr)); if (sm == nullptr) { + ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str()); sleep(1); } } -- cgit v1.2.3-59-g8ed1b From 706933754bd7087c30d8c583a786ff46bd314e19 Mon Sep 17 00:00:00 2001 From: Yichi Chen Date: Wed, 27 May 2020 16:02:33 +0800 Subject: gralloc4: Support RAW type in PlaneLayoutComponentType The patch creates RAW type in PlaneLayoutComponentType to make list complete. Bug: b/157534008 Test: VtsHalGraphicsMapperV4_0TargetTest Change-Id: I871f90756eafb848cf7489b9710f4df47f8f8ec2 --- libs/gralloc/types/include/gralloctypes/Gralloc4.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'libs') diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h index 8d12754d79..1a7c2c946a 100644 --- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h +++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h @@ -431,6 +431,12 @@ static const aidl::android::hardware::graphics::common::ExtendableType PlaneLayo static_cast( aidl::android::hardware::graphics::common::PlaneLayoutComponentType::A)}; +static const aidl::android::hardware::graphics::common::ExtendableType + PlaneLayoutComponentType_RAW = + {GRALLOC4_STANDARD_PLANE_LAYOUT_COMPONENT_TYPE, + static_cast( + aidl::android::hardware::graphics::common::PlaneLayoutComponentType::RAW)}; + /*---------------------------------------------------------------------------------------------*/ /** -- cgit v1.2.3-59-g8ed1b From 710db09fe4e9058710f713b38c7df539afb9795f Mon Sep 17 00:00:00 2001 From: Steven Thomas Date: Thu, 28 May 2020 14:12:01 -0700 Subject: Clarify FRAME_RATE_COMPATIBILITY_* params Bug: 155894036 Test: n/a Change-Id: I23124fc3da0d870aa9a8b571cd7900aabf5a1326 --- libs/nativewindow/include/android/native_window.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 25130e2a03..36aad2eced 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -236,7 +236,11 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN /** Compatibility value for ANativeWindow_setFrameRate. */ enum ANativeWindow_FrameRateCompatibility { /** - * There are no inherent restrictions on the frame rate of this window. + * There are no inherent restrictions on the frame rate of this window. When + * the system selects a frame rate other than what the app requested, the + * app will be able to run at the system frame rate without requiring pull + * down. This value should be used when displaying game content, UIs, and + * anything that isn't video. */ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0, /** @@ -246,7 +250,7 @@ enum ANativeWindow_FrameRateCompatibility { * to do pull down or use some other technique to adapt to the system's * frame rate. The user experience is likely to be worse (e.g. more frame * stuttering) than it would be if the system had chosen the app's requested - * frame rate. + * frame rate. This value should be used for video content. */ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1 }; -- cgit v1.2.3-59-g8ed1b From c43a23c1491ed1e23a1abc48bba98fff67df46de Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 29 May 2020 14:32:27 -0700 Subject: Add layer flag to allow creating an effect layer without color fill This change allows creating an effect layers without a color fill so we can avoid an additional sf transactions when creating effect layers. Fixes: 157646690 Test: go/wm-smoke Test: atest SurfaceFlinger_test Change-Id: I3d8a4f4820d7b8fb05daab697c25cff8def612c1 --- libs/gui/include/gui/ISurfaceComposerClient.h | 3 +- services/surfaceflinger/Layer.cpp | 7 ++ services/surfaceflinger/tests/Android.bp | 1 + services/surfaceflinger/tests/EffectLayer_test.cpp | 117 +++++++++++++++++++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 services/surfaceflinger/tests/EffectLayer_test.cpp (limited to 'libs') diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 6366529a10..3afbabf1dc 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -33,7 +33,7 @@ public: DECLARE_META_INTERFACE(SurfaceComposerClient) // flags for createSurface() - enum { // (keep in sync with Surface.java) + enum { // (keep in sync with SurfaceControl.java) eHidden = 0x00000004, eDestroyBackbuffer = 0x00000020, eSecure = 0x00000080, @@ -42,6 +42,7 @@ public: eProtectedByApp = 0x00000800, eProtectedByDRM = 0x00001000, eCursorWindow = 0x00002000, + eNoColorFill = 0x00004000, eFXSurfaceBufferQueue = 0x00000000, eFXSurfaceEffect = 0x00020000, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5b9dbf2922..f3d0b1016d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -119,6 +119,13 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.treeHasFrameRateVote = false; mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID; + if (args.flags & ISurfaceComposerClient::eNoColorFill) { + // Set an invalid color so there is no color fill. + mCurrentState.color.r = -1.0_hf; + mCurrentState.color.g = -1.0_hf; + mCurrentState.color.b = -1.0_hf; + } + // drawing state & current state are identical mDrawingState = mCurrentState; diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 94ebe8949b..fe2af80c98 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -22,6 +22,7 @@ cc_test { "Credentials_test.cpp", "DereferenceSurfaceControl_test.cpp", "DisplayConfigs_test.cpp", + "EffectLayer_test.cpp", "InvalidHandles_test.cpp", "LayerCallback_test.cpp", "LayerRenderTypeTransaction_test.cpp", diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp new file mode 100644 index 0000000000..3dca3916e4 --- /dev/null +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#include "LayerTransactionTest.h" + +namespace android { + +class EffectLayerTest : public LayerTransactionTest { +protected: + virtual void SetUp() { + LayerTransactionTest::SetUp(); + ASSERT_EQ(NO_ERROR, mClient->initCheck()); + + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + + mParentLayer = createColorLayer("Parent layer", Color::RED); + asTransaction([&](Transaction& t) { + t.setDisplayLayerStack(display, 0); + t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer); + t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); + }); + } + + virtual void TearDown() { + LayerTransactionTest::TearDown(); + mParentLayer = 0; + } + + sp mParentLayer; +}; + +TEST_F(EffectLayerTest, DefaultEffectLayerHasSolidBlackFill) { + sp effectLayer = + mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect, + mParentLayer.get()); + + EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; + asTransaction([&](Transaction& t) { + t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400)); + t.show(effectLayer); + }); + + { + SCOPED_TRACE("Default effect Layer has solid black fill"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 400, 400), Color::BLACK); + } +} + +TEST_F(EffectLayerTest, EffectLayerWithNoFill) { + sp effectLayer = + mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mParentLayer.get()); + + EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; + asTransaction([&](Transaction& t) { + t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400)); + t.show(effectLayer); + }); + + { + SCOPED_TRACE("Effect layer with nofill option is transparent"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 400, 400), Color::RED); + } +} + +TEST_F(EffectLayerTest, EffectLayerCanSetColor) { + sp effectLayer = + mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mParentLayer.get()); + + EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; + asTransaction([&](Transaction& t) { + t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400)); + t.setColor(effectLayer, + half3{Color::GREEN.r / 255.0f, Color::GREEN.g / 255.0f, + Color::GREEN.b / 255.0f}); + t.show(effectLayer); + }); + + { + SCOPED_TRACE("Effect Layer can set color"); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 400, 400), Color::GREEN); + } +} + +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" -- cgit v1.2.3-59-g8ed1b From 43bccf83214bbbe5558b626cd0755527ae8a5aec Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 5 Jun 2020 10:53:37 -0700 Subject: Call Layer::getLayerDebugInfo from the main thread Fixes an issue where drawing state could be accessed from a binder thread. The function also mixed current state with drawing state incorrectly. The function now only retrieves drawing state. Bug: 150226608 Test: Steps in bug doesn't repro Test: atest sffakehwc_test Change-Id: I5537c53e8214e2785473839d71fd483d1a3219b6 --- libs/gui/ISurfaceComposer.cpp | 3 +-- libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/tests/Surface_test.cpp | 2 +- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 17 +++++++---------- services/surfaceflinger/SurfaceFlinger.h | 2 +- 6 files changed, 12 insertions(+), 16 deletions(-) (limited to 'libs') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2a27a9a278..e62a61fc55 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -691,8 +691,7 @@ public: return result; } - virtual status_t getLayerDebugInfo(std::vector* outLayers) const - { + virtual status_t getLayerDebugInfo(std::vector* outLayers) { if (!outLayers) { return UNEXPECTED_NULL; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 0d33b3f695..b49fa1baf1 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -354,7 +354,7 @@ public: * * Requires the ACCESS_SURFACE_FLINGER permission. */ - virtual status_t getLayerDebugInfo(std::vector* outLayers) const = 0; + virtual status_t getLayerDebugInfo(std::vector* outLayers) = 0; virtual status_t getColorManagement(bool* outGetColorManagement) const = 0; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index a1d12a5ca6..c2b4ef93aa 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -785,7 +785,7 @@ public: return NO_ERROR; } status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; } - status_t getLayerDebugInfo(std::vector* /*layers*/) const override { + status_t getLayerDebugInfo(std::vector* /*layers*/) override { return NO_ERROR; } status_t getCompositionPreference( diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index dcc213f943..9ce0fd4bde 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1501,7 +1501,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { LayerDebugInfo info; const State& ds = getDrawingState(); info.mName = getName(); - sp parent = getParent(); + sp parent = mDrawingParent.promote(); info.mParentName = parent ? parent->getName() : "none"s; info.mType = getType(); info.mTransparentRegion = ds.activeTransparentRegion_legacy; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2e2273594e..c878457ebc 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1449,17 +1449,14 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) { return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE; } -status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) const { - TimedLock lock(mStateLock, s2ns(1), __FUNCTION__); - if (!lock.locked()) { - return TIMED_OUT; - } - - const auto display = getDefaultDisplayDeviceLocked(); +status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayers) { outLayers->clear(); - mCurrentState.traverseInZOrder( - [&](Layer* layer) { outLayers->push_back(layer->getLayerDebugInfo(display.get())); }); - + schedule([=] { + const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); + mDrawingState.traverseInZOrder([&](Layer* layer) { + outLayers->push_back(layer->getLayerDebugInfo(display.get())); + }); + }).wait(); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 113b03557f..f5be8a8034 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -466,7 +466,7 @@ private: HdrCapabilities* outCapabilities) const override; status_t enableVSyncInjections(bool enable) override; status_t injectVSync(nsecs_t when) override; - status_t getLayerDebugInfo(std::vector* outLayers) const override; + status_t getLayerDebugInfo(std::vector* outLayers) override; status_t getColorManagement(bool* outGetColorManagement) const override; status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, ui::Dataspace* outWideColorGamutDataspace, -- cgit v1.2.3-59-g8ed1b From e4623041f91c3fac633fc0f1803bc3a7c08c6eb9 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 25 Mar 2020 16:16:40 -0700 Subject: Report ANR when waited for longer than the timeout Previously, when the touched window was unresponsive, we skipped adding the gesture monitors to the touch targets. That means, when an app has ANR, gesture nav stops working, and the phone feels frozen, until the ANR dialog comes up. Another failure mode was a stuck pending event. If there is no focused window, and we have a pending key event (or any focused event), we will be waiting for a focused window to appear. That would still prevent gesture monitors from receiving further touch events. In this solution, we do not add unresponsive windows to the list of targets, but we still proceed with handling the event, meaning that the app won't get a new DOWN when it is unresponsive, but the event would still go to the gesture monitors. That change, in isolation, would also break ANR for the case when the app loses focus. To maintain the ANR functionality, we extend the ANR detection mechanism to all connections. Now, every connection is eligible to receive an ANR, even if it's a gesture monitor. We expect everything in the system to be responsive within reasonable timeouts. We also change the handling of extended ANR timeouts coming from policy. Today, the behaviour is as follows: 1. If the policy says "wait longer", then we do nothing and just keep waiting 2. If the policy says "abort", then we send the cancel events and remove the window from the window list. The "abort" approach seems incorrect, because the policy will probably not register the existing inputchannel/connection with a new window. If the user does click "close app" when the ANR dialog appears, we will anyways receive "window removed" event via setInputWindows, and will clean up the connection that way. So we don't really need to do anything other than sending "cancel events" to the window. The policy now for sending events to unresponsive windows becomes: 1. If the unresponsive window is touched, the new touch stream does not go to the window. It will go to all other places, though. 2. If the unresponsive window receives a focused event, the event still gets queued for the unresponsive window to handle. For improved ANR performance, the ANR detection is now done by introducing a helper data structure, a multiset of the timeout times. Whenever we send an event to a connection, we will calculate the time that this event will cause a timeout. We will then add this time to the multiset of times. When we check for ANR inside dispatchOnce, we will only access the smallest (soonest) timeout inside the multiset. If the current time is before this smallest timeout time, then everything is normal, and we move on. This would cost O(1). If the time is past the timeout time, it means a connection is unresponsive. In this case, we take the closest in time unresponsive entry. That entry already has the connection token, for convenience. We then raise an ANR on that connection. The entries are removed from the multiset in several cases: 1. When we receive a 'finished' signal on an entry for a specific connection 2. When the connection becomes unresponsive and we raise ANR. In that case, no need to keep checking on the same connection. Once case 1. applies to that connection, entries from that connection will again become eligible for being added to the multiset. 3. When we reset and drop everything. 4. When we cannot find a connection for an entry in the multiset, we will drop all entries from that connection. If we report ANR for an app, we do not report the second ANR until the waitQueue becomes healthy first and then becomes clogged again. If we have a focused application, but no window has focus, then nothing will happen for pointer events. They will keep going to the touched window as normal. When we receive the first focused event, however, we will start a timer. If there is no focused window added by that time, we will send an ANR for that application. This logic should be moved into WM later, because from the input perspective, it is legitimate to have an application without a focused window. This would also allow WM to remove the "setFocusedApplication" call. Bug: 143459140 Test: use the test app from the bug. The app sleeps for 10 seconds when the button is clicked. Click the button, and try to use gesture nav several times. Observe that gesture nav continues to work even after app has ANR. Observe that ANR is reported even after interacting with gesture nav. Test: Click on the app multiple times (to clog up the queue), and then wait for a long time, even after the ANR dialog shows up. Then click "wait" to not close the app. Then click again on the app. Observe that the anr dialog appears after a while. This indicates that at some point, the app processed all events, and then became eligible for anr again. Test: adb shell -t /data/nativetest64/inputflinger_tests/inputflinger_tests Test: create an app that sets "FLAG_NOT_FOCUSABLE" on its only window. Launch the app and interact with it by touch. Notice that the app does not ANR. Then, send the back key to the app (using the back gesture). Notice that in 5 seconds, we receive an ANR for this app. While the BACK key is queued up for this app, the gesture nav continues to work and the notification shade can still be pulled down. Change-Id: I2c0fd1957cda833f5fbe26368cfcaa6fea6eddaf Merged-In: I2c0fd1957cda833f5fbe26368cfcaa6fea6eddaf --- include/input/Input.h | 4 + libs/input/Input.cpp | 31 + services/inputflinger/dispatcher/Android.bp | 1 + services/inputflinger/dispatcher/AnrTracker.cpp | 73 ++ services/inputflinger/dispatcher/AnrTracker.h | 60 ++ services/inputflinger/dispatcher/Connection.cpp | 3 +- services/inputflinger/dispatcher/Connection.h | 7 +- services/inputflinger/dispatcher/Entry.cpp | 36 +- services/inputflinger/dispatcher/Entry.h | 4 + .../inputflinger/dispatcher/InputDispatcher.cpp | 665 ++++++++++-------- services/inputflinger/dispatcher/InputDispatcher.h | 86 ++- services/inputflinger/tests/Android.bp | 1 + services/inputflinger/tests/AnrTracker_test.cpp | 167 +++++ .../inputflinger/tests/InputDispatcher_test.cpp | 750 +++++++++++++++++++-- 14 files changed, 1499 insertions(+), 389 deletions(-) create mode 100644 services/inputflinger/dispatcher/AnrTracker.cpp create mode 100644 services/inputflinger/dispatcher/AnrTracker.h create mode 100644 services/inputflinger/tests/AnrTracker_test.cpp (limited to 'libs') diff --git a/include/input/Input.h b/include/input/Input.h index 9e47318203..54b4e5a737 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -462,6 +462,8 @@ public: nsecs_t eventTime); void initialize(const KeyEvent& from); + static const char* actionToString(int32_t action); + protected: int32_t mAction; int32_t mFlags; @@ -725,6 +727,8 @@ public: static const char* getLabel(int32_t axis); static int32_t getAxisFromLabel(const char* label); + static const char* actionToString(int32_t action); + protected: int32_t mAction; int32_t mActionButton; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index c2437673df..31aa685391 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -169,6 +169,18 @@ void KeyEvent::initialize(const KeyEvent& from) { mEventTime = from.mEventTime; } +const char* KeyEvent::actionToString(int32_t action) { + // Convert KeyEvent action to string + switch (action) { + case AKEY_EVENT_ACTION_DOWN: + return "DOWN"; + case AKEY_EVENT_ACTION_UP: + return "UP"; + case AKEY_EVENT_ACTION_MULTIPLE: + return "MULTIPLE"; + } + return "UNKNOWN"; +} // --- PointerCoords --- @@ -678,6 +690,25 @@ int32_t MotionEvent::getAxisFromLabel(const char* label) { return getAxisByLabel(label); } +const char* MotionEvent::actionToString(int32_t action) { + // Convert MotionEvent action to string + switch (action & AMOTION_EVENT_ACTION_MASK) { + case AMOTION_EVENT_ACTION_DOWN: + return "DOWN"; + case AMOTION_EVENT_ACTION_MOVE: + return "MOVE"; + case AMOTION_EVENT_ACTION_UP: + return "UP"; + case AMOTION_EVENT_ACTION_CANCEL: + return "CANCEL"; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + return "POINTER_DOWN"; + case AMOTION_EVENT_ACTION_POINTER_UP: + return "POINTER_UP"; + } + return "UNKNOWN"; +} + // --- FocusEvent --- void FocusEvent::initialize(int32_t id, bool hasFocus, bool inTouchMode) { diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index b242eec465..d29d8dfda3 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -22,6 +22,7 @@ cc_library_headers { filegroup { name: "libinputdispatcher_sources", srcs: [ + "AnrTracker.cpp", "Connection.cpp", "Entry.cpp", "InjectionState.cpp", diff --git a/services/inputflinger/dispatcher/AnrTracker.cpp b/services/inputflinger/dispatcher/AnrTracker.cpp new file mode 100644 index 0000000000..c3f611e7db --- /dev/null +++ b/services/inputflinger/dispatcher/AnrTracker.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AnrTracker.h" + +namespace android::inputdispatcher { + +template +static T max(const T& a, const T& b) { + return a < b ? b : a; +} + +void AnrTracker::insert(nsecs_t timeoutTime, sp token) { + mAnrTimeouts.insert(std::make_pair(timeoutTime, std::move(token))); +} + +/** + * Erase a single entry only. If there are multiple duplicate entries + * (same time, same connection), then only remove one of them. + */ +void AnrTracker::erase(nsecs_t timeoutTime, const sp& token) { + auto pair = std::make_pair(timeoutTime, token); + auto it = mAnrTimeouts.find(pair); + if (it != mAnrTimeouts.end()) { + mAnrTimeouts.erase(it); + } +} + +void AnrTracker::eraseToken(const sp& token) { + for (auto it = mAnrTimeouts.begin(); it != mAnrTimeouts.end();) { + if (it->second == token) { + it = mAnrTimeouts.erase(it); + } else { + ++it; + } + } +} + +bool AnrTracker::empty() const { + return mAnrTimeouts.empty(); +} + +// If empty() is false, return the time at which the next connection should cause an ANR +// If empty() is true, return LONG_LONG_MAX +nsecs_t AnrTracker::firstTimeout() const { + if (mAnrTimeouts.empty()) { + return std::numeric_limits::max(); + } + return mAnrTimeouts.begin()->first; +} + +const sp& AnrTracker::firstToken() const { + return mAnrTimeouts.begin()->second; +} + +void AnrTracker::clear() { + mAnrTimeouts.clear(); +} + +} // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/AnrTracker.h b/services/inputflinger/dispatcher/AnrTracker.h new file mode 100644 index 0000000000..097dba5bea --- /dev/null +++ b/services/inputflinger/dispatcher/AnrTracker.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H +#define _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H + +#include +#include +#include + +namespace android::inputdispatcher { + +/** + * Keeps track of the times when each connection is going to ANR. + * Provides the ability to quickly find the connection that is going to cause ANR next. + */ +class AnrTracker { +public: + void insert(nsecs_t timeoutTime, sp token); + void erase(nsecs_t timeoutTime, const sp& token); + void eraseToken(const sp& token); + void clear(); + + bool empty() const; + // If empty() is false, return the time at which the next connection should cause an ANR + // If empty() is true, return LONG_LONG_MAX + nsecs_t firstTimeout() const; + // Return the token of the next connection that should cause an ANR. + // Do not call this unless empty() is false, you will encounter undefined behaviour. + const sp& firstToken() const; + +private: + // Optimization: use a multiset to keep track of the event timeouts. When an event is sent + // to the InputConsumer, we add an entry to this structure. We look at the smallest value to + // determine if any of the connections is unresponsive, and to determine when we should wake + // next for the future ANR check. + // Using a multiset helps quickly look up the next timeout due. + // + // We must use a multi-set, because it is plausible (although highly unlikely) to have entries + // from the same connection and same timestamp, but different sequence numbers. + // We are not tracking sequence numbers, and just allow duplicates to exist. + std::multiset /*connectionToken*/>> mAnrTimeouts; +}; + +} // namespace android::inputdispatcher + +#endif // _UI_INPUT_INPUTDISPATCHER_ANRTRACKER_H diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp index 188212bccf..f5ea563311 100644 --- a/services/inputflinger/dispatcher/Connection.cpp +++ b/services/inputflinger/dispatcher/Connection.cpp @@ -26,8 +26,7 @@ Connection::Connection(const sp& inputChannel, bool monitor, inputChannel(inputChannel), monitor(monitor), inputPublisher(inputChannel), - inputState(idGenerator), - inputPublisherBlocked(false) {} + inputState(idGenerator) {} Connection::~Connection() {} diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h index bb3f2fee19..3b33f29dff 100644 --- a/services/inputflinger/dispatcher/Connection.h +++ b/services/inputflinger/dispatcher/Connection.h @@ -47,9 +47,10 @@ public: InputPublisher inputPublisher; InputState inputState; - // True if the socket is full and no further events can be published until - // the application consumes some of the input. - bool inputPublisherBlocked; + // True if this connection is responsive. + // If this connection is not responsive, avoid publishing more events to it until the + // application consumes some of the input. + bool responsive = true; // Queue of events that need to be published to the connection. std::deque outboundQueue; diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index 21c8ae165d..fdbb1d1b55 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -28,38 +28,6 @@ using android::base::StringPrintf; namespace android::inputdispatcher { -static std::string motionActionToString(int32_t action) { - // Convert MotionEvent action to string - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - return "DOWN"; - case AMOTION_EVENT_ACTION_MOVE: - return "MOVE"; - case AMOTION_EVENT_ACTION_UP: - return "UP"; - case AMOTION_EVENT_ACTION_CANCEL: - return "CANCEL"; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - return "POINTER_DOWN"; - case AMOTION_EVENT_ACTION_POINTER_UP: - return "POINTER_UP"; - } - return StringPrintf("%" PRId32, action); -} - -static std::string keyActionToString(int32_t action) { - // Convert KeyEvent action to string - switch (action) { - case AKEY_EVENT_ACTION_DOWN: - return "DOWN"; - case AKEY_EVENT_ACTION_UP: - return "UP"; - case AKEY_EVENT_ACTION_MULTIPLE: - return "MULTIPLE"; - } - return StringPrintf("%" PRId32, action); -} - VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) { return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source, entry.displayId}, @@ -191,7 +159,7 @@ void KeyEntry::appendDescription(std::string& msg) const { msg += StringPrintf("(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, " "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", - deviceId, source, displayId, keyActionToString(action).c_str(), flags, + deviceId, source, displayId, KeyEvent::actionToString(action), flags, keyCode, scanCode, metaState, repeatCount, policyFlags); } @@ -253,7 +221,7 @@ void MotionEntry::appendDescription(std::string& msg) const { "buttonState=0x%08x, " "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[", - deviceId, source, displayId, motionActionToString(action).c_str(), + deviceId, source, displayId, MotionEvent::actionToString(action), actionButton, flags, metaState, buttonState, motionClassificationToString(classification), edgeFlags, xPrecision, yPrecision, xCursorPosition, yCursorPosition); diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index a135409365..6b7697dde6 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -198,7 +198,11 @@ struct DispatchEntry { float globalScaleFactor; float windowXScale = 1.0f; float windowYScale = 1.0f; + // Both deliveryTime and timeoutTime are only populated when the entry is sent to the app, + // and will be undefined before that. nsecs_t deliveryTime; // time when the event was actually delivered + // An ANR will be triggered if a response for this entry is not received by timeoutTime + nsecs_t timeoutTime; // Set to the resolved ID, action and flags when the event is enqueued. int32_t resolvedEventId; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 959eeea41e..677bf7e2ec 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -90,18 +90,17 @@ constexpr nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec // before considering it stale and dropping it. constexpr nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec -// Amount of time to allow touch events to be streamed out to a connection before requiring -// that the first event be finished. This value extends the ANR timeout by the specified -// amount. For example, if streaming is allowed to get ahead by one second relative to the -// queue of waiting unfinished events, then ANRs will similarly be delayed by one second. -constexpr nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec - // Log a warning when an event takes longer than this to process, even if an ANR does not occur. constexpr nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec // Log a warning when an interception call takes longer than this to process. constexpr std::chrono::milliseconds SLOW_INTERCEPTION_THRESHOLD = 50ms; +// Additional key latency in case a connection is still processing some motion events. +// This will help with the case when a user touched a button that opens a new window, +// and gives us the chance to dispatch the key to this new window. +constexpr std::chrono::nanoseconds KEY_WAITING_FOR_EVENTS_TIMEOUT = 500ms; + // Number of recent events to keep for debugging purposes. constexpr size_t RECENT_QUEUE_MAX_SIZE = 10; @@ -409,8 +408,7 @@ InputDispatcher::InputDispatcher(const sp& polic // To avoid leaking stack in case that call never comes, and for tests, // initialize it here anyways. mInTouchMode(true), - mFocusedDisplayId(ADISPLAY_ID_DEFAULT), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { + mFocusedDisplayId(ADISPLAY_ID_DEFAULT) { mLooper = new Looper(false); mReporter = createInputReporter(); @@ -470,6 +468,11 @@ void InputDispatcher::dispatchOnce() { nextWakeupTime = LONG_LONG_MIN; } + // If we are still waiting for ack on some events, + // we might have to wake up earlier to check if an app is anr'ing. + const nsecs_t nextAnrCheck = processAnrsLocked(); + nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck); + // We are about to enter an infinitely long sleep, because we have no commands or // pending or queued events if (nextWakeupTime == LONG_LONG_MAX) { @@ -483,6 +486,55 @@ void InputDispatcher::dispatchOnce() { mLooper->pollOnce(timeoutMillis); } +/** + * Check if any of the connections' wait queues have events that are too old. + * If we waited for events to be ack'ed for more than the window timeout, raise an ANR. + * Return the time at which we should wake up next. + */ +nsecs_t InputDispatcher::processAnrsLocked() { + const nsecs_t currentTime = now(); + nsecs_t nextAnrCheck = LONG_LONG_MAX; + // Check if we are waiting for a focused window to appear. Raise ANR if waited too long + if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) { + if (currentTime >= *mNoFocusedWindowTimeoutTime) { + onAnrLocked(mAwaitedFocusedApplication); + mAwaitedFocusedApplication.clear(); + return LONG_LONG_MIN; + } else { + // Keep waiting + const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime); + ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining); + nextAnrCheck = *mNoFocusedWindowTimeoutTime; + } + } + + // Check if any connection ANRs are due + nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout()); + if (currentTime < nextAnrCheck) { // most likely scenario + return nextAnrCheck; // everything is normal. Let's check again at nextAnrCheck + } + + // If we reached here, we have an unresponsive connection. + sp connection = getConnectionLocked(mAnrTracker.firstToken()); + if (connection == nullptr) { + ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout()); + return nextAnrCheck; + } + connection->responsive = false; + // Stop waking up for this unresponsive connection + mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken()); + onAnrLocked(connection); + return LONG_LONG_MIN; +} + +nsecs_t InputDispatcher::getDispatchingTimeoutLocked(const sp& token) { + sp window = getWindowHandleLocked(token); + if (window != nullptr) { + return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT).count(); + } + return DEFAULT_INPUT_DISPATCHING_TIMEOUT.count(); +} + void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); @@ -546,9 +598,6 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { pokeUserActivityLocked(*mPendingEvent); } - - // Get ready to dispatch the event. - resetAnrTimeoutsLocked(); } // Now we have an event to dispatch. @@ -642,11 +691,14 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { * Return false otherwise (the default behaviour) */ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) { - bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN && + const bool isPointerDownEvent = motionEntry.action == AMOTION_EVENT_ACTION_DOWN && (motionEntry.source & AINPUT_SOURCE_CLASS_POINTER); - if (isPointerDownEvent && - mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && - mInputTargetWaitApplicationToken != nullptr) { + + // Optimize case where the current application is unresponsive and the user + // decides to touch a window in a different application. + // If the application takes too long to catch up then we drop all events preceding + // the touch into the other window. + if (isPointerDownEvent && mAwaitedFocusedApplication != nullptr) { int32_t displayId = motionEntry.displayId; int32_t x = static_cast( motionEntry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); @@ -655,12 +707,41 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, nullptr); if (touchedWindowHandle != nullptr && - touchedWindowHandle->getApplicationToken() != mInputTargetWaitApplicationToken) { + touchedWindowHandle->getApplicationToken() != + mAwaitedFocusedApplication->getApplicationToken()) { // User touched a different application than the one we are waiting on. - // Flag the event, and start pruning the input queue. - ALOGI("Pruning input queue because user touched a different application"); + ALOGI("Pruning input queue because user touched a different application while waiting " + "for %s", + mAwaitedFocusedApplication->getName().c_str()); return true; } + + // Alternatively, maybe there's a gesture monitor that could handle this event + std::vector gestureMonitors = + findTouchedGestureMonitorsLocked(displayId, {}); + for (TouchedMonitor& gestureMonitor : gestureMonitors) { + sp connection = + getConnectionLocked(gestureMonitor.monitor.inputChannel->getConnectionToken()); + if (connection->responsive) { + // This monitor could take more input. Drop all events preceding this + // event, so that gesture monitor could get a chance to receive the stream + ALOGW("Pruning the input queue because %s is unresponsive, but we have a " + "responsive gesture monitor that may handle the event", + mAwaitedFocusedApplication->getName().c_str()); + return true; + } + } + } + + // Prevent getting stuck: if we have a pending key event, and some motion events that have not + // yet been processed by some connections, the dispatcher will wait for these motion + // events to be processed before dispatching the key event. This is because these motion events + // may cause a new window to be launched, which the user might expect to receive focus. + // To prevent waiting forever for such events, just send the key to the currently focused window + if (isPointerDownEvent && mKeyIsWaitingForEventsTimeout) { + ALOGD("Received a new pointer down event, stop waiting for events to process and " + "just send the pending key event to the focused window."); + mKeyIsWaitingForEventsTimeout = now(); } return false; } @@ -694,10 +775,6 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { } case EventEntry::Type::MOTION: { - // Optimize case where the current application is unresponsive and the user - // decides to touch a window in a different application. - // If the application takes too long to catch up then we drop all events preceding - // the touch into the other window. if (shouldPruneInboundQueueLocked(static_cast(*entry))) { mNextUnblockedEvent = entry; needWake = true; @@ -912,7 +989,6 @@ void InputDispatcher::drainInboundQueueLocked() { void InputDispatcher::releasePendingEventLocked() { if (mPendingEvent) { - resetAnrTimeoutsLocked(); releaseInboundEventLocked(mPendingEvent); mPendingEvent = nullptr; } @@ -1294,109 +1370,29 @@ void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* event } } -int32_t InputDispatcher::handleTargetsNotReadyLocked( - nsecs_t currentTime, const EventEntry& entry, - const sp& applicationHandle, - const sp& windowHandle, nsecs_t* nextWakeupTime, const char* reason) { - if (applicationHandle == nullptr && windowHandle == nullptr) { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { - if (DEBUG_FOCUS) { - ALOGD("Waiting for system to become ready for input. Reason: %s", reason); - } - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = LONG_LONG_MAX; - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationToken.clear(); - } - } else { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { - ALOGI("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason); - std::chrono::nanoseconds timeout; - if (windowHandle != nullptr) { - timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else if (applicationHandle != nullptr) { - timeout = - applicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else { - timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; - } - - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = currentTime + timeout.count(); - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationToken.clear(); - - if (windowHandle != nullptr) { - mInputTargetWaitApplicationToken = windowHandle->getApplicationToken(); - } - if (mInputTargetWaitApplicationToken == nullptr && applicationHandle != nullptr) { - mInputTargetWaitApplicationToken = applicationHandle->getApplicationToken(); - } - } - } - - if (mInputTargetWaitTimeoutExpired) { - return INPUT_EVENT_INJECTION_TIMED_OUT; - } - - if (currentTime >= mInputTargetWaitTimeoutTime) { - onAnrLocked(currentTime, applicationHandle, windowHandle, entry.eventTime, - mInputTargetWaitStartTime, reason); - - // Force poll loop to wake up immediately on next iteration once we get the - // ANR response back from the policy. - *nextWakeupTime = LONG_LONG_MIN; - return INPUT_EVENT_INJECTION_PENDING; - } else { - // Force poll loop to wake up when timeout is due. - if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { - *nextWakeupTime = mInputTargetWaitTimeoutTime; - } - return INPUT_EVENT_INJECTION_PENDING; - } -} - -void InputDispatcher::removeWindowByTokenLocked(const sp& token) { - for (std::pair& pair : mTouchStatesByDisplay) { - TouchState& state = pair.second; - state.removeWindowByToken(token); - } -} - -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked( - nsecs_t timeoutExtension, const sp& inputConnectionToken) { - if (timeoutExtension > 0) { - // Extend the timeout. - mInputTargetWaitTimeoutTime = now() + timeoutExtension; - } else { - // Give up. - mInputTargetWaitTimeoutExpired = true; - - // Input state will not be realistic. Mark it out of sync. - sp connection = getConnectionLocked(inputConnectionToken); - if (connection != nullptr) { - removeWindowByTokenLocked(inputConnectionToken); - - if (connection->status == Connection::STATUS_NORMAL) { - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "application not responding"); - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - } +void InputDispatcher::cancelEventsForAnrLocked(const sp& connection) { + // We will not be breaking any connections here, even if the policy wants us to abort dispatch. + // If the policy decides to close the app, we will get a channel removal event via + // unregisterInputChannel, and will clean up the connection that way. We are already not + // sending new pointers to the connection when it blocked, but focused events will continue to + // pile up. + ALOGW("Canceling events for %s because it is unresponsive", + connection->inputChannel->getName().c_str()); + if (connection->status == Connection::STATUS_NORMAL) { + CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, + "application not responding"); + synthesizeCancelationEventsForConnectionLocked(connection, options); } } -void InputDispatcher::resetAnrTimeoutsLocked() { +void InputDispatcher::resetNoFocusedWindowTimeoutLocked() { if (DEBUG_FOCUS) { ALOGD("Resetting ANR timeouts."); } // Reset input target wait timeout. - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; - mInputTargetWaitApplicationToken.clear(); + mNoFocusedWindowTimeoutTime = std::nullopt; + mAwaitedFocusedApplication.clear(); } /** @@ -1427,6 +1423,36 @@ int32_t InputDispatcher::getTargetDisplayId(const EventEntry& entry) { return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId; } +bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime, + const char* focusedWindowName) { + if (mAnrTracker.empty()) { + // already processed all events that we waited for + mKeyIsWaitingForEventsTimeout = std::nullopt; + return false; + } + + if (!mKeyIsWaitingForEventsTimeout.has_value()) { + // Start the timer + ALOGD("Waiting to send key to %s because there are unprocessed events that may cause " + "focus to change", + focusedWindowName); + mKeyIsWaitingForEventsTimeout = currentTime + KEY_WAITING_FOR_EVENTS_TIMEOUT.count(); + return true; + } + + // We still have pending events, and already started the timer + if (currentTime < *mKeyIsWaitingForEventsTimeout) { + return true; // Still waiting + } + + // Waited too long, and some connection still hasn't processed all motions + // Just send the key to the focused window + ALOGW("Dispatching key to %s even though there are other unprocessed events", + focusedWindowName); + mKeyIsWaitingForEventsTimeout = std::nullopt; + return false; +} + int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry& entry, std::vector& inputTargets, @@ -1441,31 +1467,70 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, // If there is no currently focused window and no focused application // then drop the event. - if (focusedWindowHandle == nullptr) { - if (focusedApplicationHandle != nullptr) { - return handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, - nullptr, nextWakeupTime, - "Waiting because no window has focus but there is " - "a focused application that may eventually add a " - "window when it finishes starting up."); - } - - ALOGI("Dropping event because there is no focused window or focused application in display " - "%" PRId32 ".", - displayId); + if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) { + ALOGI("Dropping %s event because there is no focused window or focused application in " + "display %" PRId32 ".", + EventEntry::typeToString(entry.type), displayId); return INPUT_EVENT_INJECTION_FAILED; } + // Compatibility behavior: raise ANR if there is a focused application, but no focused window. + // Only start counting when we have a focused event to dispatch. The ANR is canceled if we + // start interacting with another application via touch (app switch). This code can be removed + // if the "no focused window ANR" is moved to the policy. Input doesn't know whether + // an app is expected to have a focused window. + if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) { + if (!mNoFocusedWindowTimeoutTime.has_value()) { + // We just discovered that there's no focused window. Start the ANR timer + const nsecs_t timeout = focusedApplicationHandle->getDispatchingTimeout( + DEFAULT_INPUT_DISPATCHING_TIMEOUT.count()); + mNoFocusedWindowTimeoutTime = currentTime + timeout; + mAwaitedFocusedApplication = focusedApplicationHandle; + ALOGW("Waiting because no window has focus but %s may eventually add a " + "window when it finishes starting up. Will wait for %" PRId64 "ms", + mAwaitedFocusedApplication->getName().c_str(), ns2ms(timeout)); + *nextWakeupTime = *mNoFocusedWindowTimeoutTime; + return INPUT_EVENT_INJECTION_PENDING; + } else if (currentTime > *mNoFocusedWindowTimeoutTime) { + // Already raised ANR. Drop the event + ALOGE("Dropping %s event because there is no focused window", + EventEntry::typeToString(entry.type)); + return INPUT_EVENT_INJECTION_FAILED; + } else { + // Still waiting for the focused window + return INPUT_EVENT_INJECTION_PENDING; + } + } + + // we have a valid, non-null focused window + resetNoFocusedWindowTimeoutLocked(); + // Check permissions. if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) { return INPUT_EVENT_INJECTION_PERMISSION_DENIED; } - // Check whether the window is ready for more input. - reason = checkWindowReadyForMoreInputLocked(currentTime, focusedWindowHandle, entry, "focused"); - if (!reason.empty()) { - return handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle, - focusedWindowHandle, nextWakeupTime, reason.c_str()); + if (focusedWindowHandle->getInfo()->paused) { + ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str()); + return INPUT_EVENT_INJECTION_PENDING; + } + + // If the event is a key event, then we must wait for all previous events to + // complete before delivering it because previous events may have the + // side-effect of transferring focus to a different window and we want to + // ensure that the following keys are sent to the new window. + // + // Suppose the user touches a button in a window then immediately presses "A". + // If the button causes a pop-up window to appear then we want to ensure that + // the "A" key is delivered to the new pop-up window. This is because users + // often anticipate pending UI changes when typing on a keyboard. + // To obtain this behavior, we must serialize key events with respect to all + // prior input events. + if (entry.type == EventEntry::Type::KEY) { + if (shouldWaitToSendKeyLocked(currentTime, focusedWindowHandle->getName().c_str())) { + *nextWakeupTime = *mKeyIsWaitingForEventsTimeout; + return INPUT_EVENT_INJECTION_PENDING; + } } // Success! Output targets. @@ -1477,6 +1542,32 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, return INPUT_EVENT_INJECTION_SUCCEEDED; } +/** + * Given a list of monitors, remove the ones we cannot find a connection for, and the ones + * that are currently unresponsive. + */ +std::vector InputDispatcher::selectResponsiveMonitorsLocked( + const std::vector& monitors) const { + std::vector responsiveMonitors; + std::copy_if(monitors.begin(), monitors.end(), std::back_inserter(responsiveMonitors), + [this](const TouchedMonitor& monitor) REQUIRES(mLock) { + sp connection = getConnectionLocked( + monitor.monitor.inputChannel->getConnectionToken()); + if (connection == nullptr) { + ALOGE("Could not find connection for monitor %s", + monitor.monitor.inputChannel->getName().c_str()); + return false; + } + if (!connection->responsive) { + ALOGW("Unresponsive monitor %s will not get the new gesture", + connection->inputChannel->getName().c_str()); + return false; + } + return true; + }); + return responsiveMonitors; +} + int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry& entry, std::vector& inputTargets, @@ -1592,6 +1683,29 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, newTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); } + if (newTouchedWindowHandle != nullptr && newTouchedWindowHandle->getInfo()->paused) { + ALOGI("Not sending touch event to %s because it is paused", + newTouchedWindowHandle->getName().c_str()); + newTouchedWindowHandle = nullptr; + } + + if (newTouchedWindowHandle != nullptr) { + sp connection = getConnectionLocked(newTouchedWindowHandle->getToken()); + if (connection == nullptr) { + ALOGI("Could not find connection for %s", + newTouchedWindowHandle->getName().c_str()); + newTouchedWindowHandle = nullptr; + } else if (!connection->responsive) { + // don't send the new touch to an unresponsive window + ALOGW("Unresponsive window %s will not get the new gesture at %" PRIu64, + newTouchedWindowHandle->getName().c_str(), entry.eventTime); + newTouchedWindowHandle = nullptr; + } + } + + // Also don't send the new touch event to unresponsive gesture monitors + newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors); + if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) { ALOGI("Dropping event because there is no touchable window or gesture monitor at " "(%d, %d) in display %" PRId32 ".", @@ -1758,21 +1872,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, } } - // Ensure all touched foreground windows are ready for new input. - for (const TouchedWindow& touchedWindow : tempTouchState.windows) { - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - // Check whether the window is ready for more input. - std::string reason = - checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, - entry, "touched"); - if (!reason.empty()) { - return handleTargetsNotReadyLocked(currentTime, entry, nullptr, - touchedWindow.windowHandle, nextWakeupTime, - reason.c_str()); - } - } - } - // If this is the first pointer going down and the touched window has a wallpaper // then also add the touched wallpaper windows so they are locked in for the duration // of the touch gesture. @@ -2050,92 +2149,6 @@ bool InputDispatcher::isWindowObscuredLocked(const sp& window return false; } -std::string InputDispatcher::checkWindowReadyForMoreInputLocked( - nsecs_t currentTime, const sp& windowHandle, - const EventEntry& eventEntry, const char* targetType) { - // If the window is paused then keep waiting. - if (windowHandle->getInfo()->paused) { - return StringPrintf("Waiting because the %s window is paused.", targetType); - } - - // If the window's connection is not registered then keep waiting. - sp connection = getConnectionLocked(windowHandle->getToken()); - if (connection == nullptr) { - return StringPrintf("Waiting because the %s window's input channel is not " - "registered with the input dispatcher. The window may be in the " - "process of being removed.", - targetType); - } - - // If the connection is dead then keep waiting. - if (connection->status != Connection::STATUS_NORMAL) { - return StringPrintf("Waiting because the %s window's input connection is %s." - "The window may be in the process of being removed.", - targetType, connection->getStatusLabel()); - } - - // If the connection is backed up then keep waiting. - if (connection->inputPublisherBlocked) { - return StringPrintf("Waiting because the %s window's input channel is full. " - "Outbound queue length: %zu. Wait queue length: %zu.", - targetType, connection->outboundQueue.size(), - connection->waitQueue.size()); - } - - // Ensure that the dispatch queues aren't too far backed up for this event. - if (eventEntry.type == EventEntry::Type::KEY) { - // If the event is a key event, then we must wait for all previous events to - // complete before delivering it because previous events may have the - // side-effect of transferring focus to a different window and we want to - // ensure that the following keys are sent to the new window. - // - // Suppose the user touches a button in a window then immediately presses "A". - // If the button causes a pop-up window to appear then we want to ensure that - // the "A" key is delivered to the new pop-up window. This is because users - // often anticipate pending UI changes when typing on a keyboard. - // To obtain this behavior, we must serialize key events with respect to all - // prior input events. - if (!connection->outboundQueue.empty() || !connection->waitQueue.empty()) { - return StringPrintf("Waiting to send key event because the %s window has not " - "finished processing all of the input events that were previously " - "delivered to it. Outbound queue length: %zu. Wait queue length: " - "%zu.", - targetType, connection->outboundQueue.size(), - connection->waitQueue.size()); - } - } else { - // Touch events can always be sent to a window immediately because the user intended - // to touch whatever was visible at the time. Even if focus changes or a new - // window appears moments later, the touch event was meant to be delivered to - // whatever window happened to be on screen at the time. - // - // Generic motion events, such as trackball or joystick events are a little trickier. - // Like key events, generic motion events are delivered to the focused window. - // Unlike key events, generic motion events don't tend to transfer focus to other - // windows and it is not important for them to be serialized. So we prefer to deliver - // generic motion events as soon as possible to improve efficiency and reduce lag - // through batching. - // - // The one case where we pause input event delivery is when the wait queue is piling - // up with lots of events because the application is not responding. - // This condition ensures that ANRs are detected reliably. - if (!connection->waitQueue.empty() && - currentTime >= - connection->waitQueue.front()->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) { - return StringPrintf("Waiting to send non-key event because the %s window has not " - "finished processing certain input events that were delivered to " - "it over " - "%0.1fms ago. Wait queue length: %zu. Wait queue head age: " - "%0.1fms.", - targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f, - connection->waitQueue.size(), - (currentTime - connection->waitQueue.front()->deliveryTime) * - 0.000001f); - } - } - return ""; -} - std::string InputDispatcher::getApplicationWindowLabel( const sp& applicationHandle, const sp& windowHandle) { @@ -2535,6 +2548,9 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.front(); dispatchEntry->deliveryTime = currentTime; + const nsecs_t timeout = + getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken()); + dispatchEntry->timeoutTime = currentTime + timeout; // Publish the event. status_t status; @@ -2654,7 +2670,6 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, "waiting for the application to catch up", connection->getInputChannelName().c_str()); #endif - connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " @@ -2671,6 +2686,10 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, dispatchEntry)); traceOutboundQueueLength(connection); connection->waitQueue.push_back(dispatchEntry); + if (connection->responsive) { + mAnrTracker.insert(dispatchEntry->timeoutTime, + connection->inputChannel->getConnectionToken()); + } traceWaitQueueLength(connection); } } @@ -2705,8 +2724,6 @@ void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, connection->getInputChannelName().c_str(), seq, toString(handled)); #endif - connection->inputPublisherBlocked = false; - if (connection->status == Connection::STATUS_BROKEN || connection->status == Connection::STATUS_ZOMBIE) { return; @@ -3862,15 +3879,17 @@ void InputDispatcher::setFocusedApplication( sp oldFocusedApplicationHandle = getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); + + if (oldFocusedApplicationHandle == mAwaitedFocusedApplication && + inputApplicationHandle != oldFocusedApplicationHandle) { + resetNoFocusedWindowTimeoutLocked(); + } + if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) { if (oldFocusedApplicationHandle != inputApplicationHandle) { - if (oldFocusedApplicationHandle != nullptr) { - resetAnrTimeoutsLocked(); - } mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle; } } else if (oldFocusedApplicationHandle != nullptr) { - resetAnrTimeoutsLocked(); oldFocusedApplicationHandle.clear(); mFocusedApplicationHandlesByDisplay.erase(displayId); } @@ -3951,7 +3970,7 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) { if (mDispatchFrozen && !frozen) { - resetAnrTimeoutsLocked(); + resetNoFocusedWindowTimeoutLocked(); } if (mDispatchEnabled && !enabled) { @@ -4091,8 +4110,9 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { resetKeyRepeatLocked(); releasePendingEventLocked(); drainInboundQueueLocked(); - resetAnrTimeoutsLocked(); + resetNoFocusedWindowTimeoutLocked(); + mAnrTracker.clear(); mTouchStatesByDisplay.clear(); mLastHoverWindowHandle.clear(); mReplacedKeys.clear(); @@ -4289,11 +4309,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { for (const auto& pair : mConnectionsByFd) { const sp& connection = pair.second; dump += StringPrintf(INDENT2 "%i: channelName='%s', windowName='%s', " - "status=%s, monitor=%s, inputPublisherBlocked=%s\n", + "status=%s, monitor=%s, responsive=%s\n", pair.first, connection->getInputChannelName().c_str(), connection->getWindowName().c_str(), connection->getStatusLabel(), - toString(connection->monitor), - toString(connection->inputPublisherBlocked)); + toString(connection->monitor), toString(connection->responsive)); if (!connection->outboundQueue.empty()) { dump += StringPrintf(INDENT3 "OutboundQueue: length=%zu\n", @@ -4561,6 +4580,7 @@ sp InputDispatcher::getConnectionLocked(const sp& inputConn } void InputDispatcher::removeConnectionLocked(const sp& connection) { + mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken()); removeByValue(mConnectionsByFd, connection); } @@ -4598,17 +4618,69 @@ void InputDispatcher::onFocusChangedLocked(const sp& oldFocus postCommandLocked(std::move(commandEntry)); } -void InputDispatcher::onAnrLocked(nsecs_t currentTime, - const sp& applicationHandle, - const sp& windowHandle, nsecs_t eventTime, - nsecs_t waitStartTime, const char* reason) { - float dispatchLatency = (currentTime - eventTime) * 0.000001f; - float waitDuration = (currentTime - waitStartTime) * 0.000001f; - ALOGI("Application is not responding: %s. " - "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), dispatchLatency, - waitDuration, reason); +void InputDispatcher::onAnrLocked(const sp& connection) { + // Since we are allowing the policy to extend the timeout, maybe the waitQueue + // is already healthy again. Don't raise ANR in this situation + if (connection->waitQueue.empty()) { + ALOGI("Not raising ANR because the connection %s has recovered", + connection->inputChannel->getName().c_str()); + return; + } + /** + * The "oldestEntry" is the entry that was first sent to the application. That entry, however, + * may not be the one that caused the timeout to occur. One possibility is that window timeout + * has changed. This could cause newer entries to time out before the already dispatched + * entries. In that situation, the newest entries caused ANR. But in all likelihood, the app + * processes the events linearly. So providing information about the oldest entry seems to be + * most useful. + */ + DispatchEntry* oldestEntry = *connection->waitQueue.begin(); + const nsecs_t currentWait = now() - oldestEntry->deliveryTime; + std::string reason = + android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s", + connection->inputChannel->getName().c_str(), + ns2ms(currentWait), + oldestEntry->eventEntry->getDescription().c_str()); + + updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()), + reason); + + std::unique_ptr commandEntry = + std::make_unique(&InputDispatcher::doNotifyAnrLockedInterruptible); + commandEntry->inputApplicationHandle = nullptr; + commandEntry->inputChannel = connection->inputChannel; + commandEntry->reason = std::move(reason); + postCommandLocked(std::move(commandEntry)); +} +void InputDispatcher::onAnrLocked(const sp& application) { + std::string reason = android::base::StringPrintf("%s does not have a focused window", + application->getName().c_str()); + + updateLastAnrStateLocked(application, reason); + + std::unique_ptr commandEntry = + std::make_unique(&InputDispatcher::doNotifyAnrLockedInterruptible); + commandEntry->inputApplicationHandle = application; + commandEntry->inputChannel = nullptr; + commandEntry->reason = std::move(reason); + postCommandLocked(std::move(commandEntry)); +} + +void InputDispatcher::updateLastAnrStateLocked(const sp& window, + const std::string& reason) { + const std::string windowLabel = getApplicationWindowLabel(nullptr, window); + updateLastAnrStateLocked(windowLabel, reason); +} + +void InputDispatcher::updateLastAnrStateLocked(const sp& application, + const std::string& reason) { + const std::string windowLabel = getApplicationWindowLabel(application, nullptr); + updateLastAnrStateLocked(windowLabel, reason); +} + +void InputDispatcher::updateLastAnrStateLocked(const std::string& windowLabel, + const std::string& reason) { // Capture a record of the InputDispatcher state at the time of the ANR. time_t t = time(nullptr); struct tm tm; @@ -4618,21 +4690,9 @@ void InputDispatcher::onAnrLocked(nsecs_t currentTime, mLastAnrState.clear(); mLastAnrState += INDENT "ANR:\n"; mLastAnrState += StringPrintf(INDENT2 "Time: %s\n", timestr); - mLastAnrState += - StringPrintf(INDENT2 "Window: %s\n", - getApplicationWindowLabel(applicationHandle, windowHandle).c_str()); - mLastAnrState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); - mLastAnrState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); - mLastAnrState += StringPrintf(INDENT2 "Reason: %s\n", reason); + mLastAnrState += StringPrintf(INDENT2 "Reason: %s\n", reason.c_str()); + mLastAnrState += StringPrintf(INDENT2 "Window: %s\n", windowLabel.c_str()); dumpDispatchStateLocked(mLastAnrState); - - std::unique_ptr commandEntry = - std::make_unique(&InputDispatcher::doNotifyAnrLockedInterruptible); - commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputChannel = - windowHandle != nullptr ? getInputChannelLocked(windowHandle->getToken()) : nullptr; - commandEntry->reason = reason; - postCommandLocked(std::move(commandEntry)); } void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) { @@ -4673,13 +4733,50 @@ void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) mLock.lock(); - resumeAfterTargetsNotReadyTimeoutLocked(timeoutExtension, token); + if (timeoutExtension > 0) { + extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension); + } else { + // stop waking up for events in this connection, it is already not responding + sp connection = getConnectionLocked(token); + if (connection == nullptr) { + return; + } + cancelEventsForAnrLocked(connection); + } +} + +void InputDispatcher::extendAnrTimeoutsLocked(const sp& application, + const sp& connectionToken, + nsecs_t timeoutExtension) { + sp connection = getConnectionLocked(connectionToken); + if (connection == nullptr) { + if (mNoFocusedWindowTimeoutTime.has_value() && application != nullptr) { + // Maybe ANR happened because there's no focused window? + mNoFocusedWindowTimeoutTime = now() + timeoutExtension; + mAwaitedFocusedApplication = application; + } else { + // It's also possible that the connection already disappeared. No action necessary. + } + return; + } + + ALOGI("Raised ANR, but the policy wants to keep waiting on %s for %" PRId64 "ms longer", + connection->inputChannel->getName().c_str(), ns2ms(timeoutExtension)); + + connection->responsive = true; + const nsecs_t newTimeout = now() + timeoutExtension; + for (DispatchEntry* entry : connection->waitQueue) { + if (newTimeout >= entry->timeoutTime) { + // Already removed old entries when connection was marked unresponsive + entry->timeoutTime = newTimeout; + mAnrTracker.insert(entry->timeoutTime, connectionToken); + } + } } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { KeyEntry* entry = commandEntry->keyEntry; - KeyEvent event = createKeyEvent(*entry); mLock.unlock(); @@ -4713,6 +4810,20 @@ void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntr mLock.lock(); } +/** + * Connection is responsive if it has no events in the waitQueue that are older than the + * current time. + */ +static bool isConnectionResponsive(const Connection& connection) { + const nsecs_t currentTime = now(); + for (const DispatchEntry* entry : connection.waitQueue) { + if (entry->timeoutTime < currentTime) { + return false; + } + } + return true; +} + void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) { sp connection = commandEntry->connection; const nsecs_t finishTime = commandEntry->eventTime; @@ -4725,7 +4836,6 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c return; } DispatchEntry* dispatchEntry = *dispatchEntryIt; - const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(), @@ -4754,6 +4864,11 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c if (dispatchEntryIt != connection->waitQueue.end()) { dispatchEntry = *dispatchEntryIt; connection->waitQueue.erase(dispatchEntryIt); + mAnrTracker.erase(dispatchEntry->timeoutTime, + connection->inputChannel->getConnectionToken()); + if (!connection->responsive) { + connection->responsive = isConnectionResponsive(*connection); + } traceWaitQueueLength(connection); if (restartEvent && connection->status == Connection::STATUS_NORMAL) { connection->outboundQueue.push_front(dispatchEntry); diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 1980435b5a..7c2028ab29 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -17,6 +17,7 @@ #ifndef _UI_INPUT_DISPATCHER_H #define _UI_INPUT_DISPATCHER_H +#include "AnrTracker.h" #include "CancelationOptions.h" #include "Entry.h" #include "InjectionState.h" @@ -216,7 +217,6 @@ private: std::optional findGestureMonitorDisplayByTokenLocked(const sp& token) REQUIRES(mLock); - // Input channels that will receive a copy of all input events sent to the provided display. std::unordered_map> mGlobalMonitorsByDisplay GUARDED_BY(mLock); @@ -274,6 +274,9 @@ private: bool runCommandsLockedInterruptible() REQUIRES(mLock); void postCommandLocked(std::unique_ptr commandEntry) REQUIRES(mLock); + nsecs_t processAnrsLocked() REQUIRES(mLock); + nsecs_t getDispatchingTimeoutLocked(const sp& token) REQUIRES(mLock); + // Input filter processing. bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock); bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock); @@ -344,38 +347,53 @@ private: void logOutboundKeyDetails(const char* prefix, const KeyEntry& entry); void logOutboundMotionDetails(const char* prefix, const MotionEntry& entry); - // Keeping track of ANR timeouts. - enum InputTargetWaitCause { - INPUT_TARGET_WAIT_CAUSE_NONE, - INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, - INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, - }; - - InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock); - nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock); - nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock); - bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock); - sp mInputTargetWaitApplicationToken GUARDED_BY(mLock); + /** + * This field is set if there is no focused window, and we have an event that requires + * a focused window to be dispatched (for example, a KeyEvent). + * When this happens, we will wait until *mNoFocusedWindowTimeoutTime before + * dropping the event and raising an ANR for that application. + * This is useful if an application is slow to add a focused window. + */ + std::optional mNoFocusedWindowTimeoutTime GUARDED_BY(mLock); bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock); - // Contains the last window which received a hover event. - sp mLastHoverWindowHandle GUARDED_BY(mLock); + /** + * Time to stop waiting for the events to be processed while trying to dispatch a key. + * When this time expires, we just send the pending key event to the currently focused window, + * without waiting on other events to be processed first. + */ + std::optional mKeyIsWaitingForEventsTimeout GUARDED_BY(mLock); + bool shouldWaitToSendKeyLocked(nsecs_t currentTime, const char* focusedWindowName) + REQUIRES(mLock); - // Finding targets for input events. - int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry& entry, - const sp& applicationHandle, - const sp& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) + /** + * The focused application at the time when no focused window was present. + * Used to raise an ANR when we have no focused window. + */ + sp mAwaitedFocusedApplication GUARDED_BY(mLock); + + // Optimization: AnrTracker is used to quickly find which connection is due for a timeout next. + // AnrTracker must be kept in-sync with all responsive connection.waitQueues. + // If a connection is not responsive, then the entries should not be added to the AnrTracker. + // Once a connection becomes unresponsive, its entries are removed from AnrTracker to + // prevent unneeded wakeups. + AnrTracker mAnrTracker GUARDED_BY(mLock); + void extendAnrTimeoutsLocked(const sp& application, + const sp& connectionToken, nsecs_t timeoutExtension) REQUIRES(mLock); - void removeWindowByTokenLocked(const sp& token) REQUIRES(mLock); + // Contains the last window which received a hover event. + sp mLastHoverWindowHandle GUARDED_BY(mLock); - void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp& inputConnectionToken) - REQUIRES(mLock); + void cancelEventsForAnrLocked(const sp& connection) REQUIRES(mLock); nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) REQUIRES(mLock); - void resetAnrTimeoutsLocked() REQUIRES(mLock); + // If a focused application changes, we should stop counting down the "no focused window" time, + // because we will have no way of knowing when the previous application actually added a window. + // This also means that we will miss cases like pulling down notification shade when the + // focused application does not have a focused window (no ANR will be raised if notification + // shade is pulled down while we are counting down the timeout). + void resetNoFocusedWindowTimeoutLocked() REQUIRES(mLock); int32_t getTargetDisplayId(const EventEntry& entry); int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry& entry, @@ -388,6 +406,8 @@ private: std::vector findTouchedGestureMonitorsLocked( int32_t displayId, const std::vector>& portalWindows) const REQUIRES(mLock); + std::vector selectResponsiveMonitorsLocked( + const std::vector& gestureMonitors) const REQUIRES(mLock); void addWindowTargetLocked(const sp& windowHandle, int32_t targetFlags, BitSet32 pointerIds, std::vector& inputTargets) @@ -406,11 +426,6 @@ private: std::string getApplicationWindowLabel(const sp& applicationHandle, const sp& windowHandle); - std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp& windowHandle, - const EventEntry& eventEntry, - const char* targetType) REQUIRES(mLock); - // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work // with the mutex held makes it easier to ensure that connection invariants are maintained. @@ -480,9 +495,14 @@ private: REQUIRES(mLock); void onFocusChangedLocked(const sp& oldFocus, const sp& newFocus) REQUIRES(mLock); - void onAnrLocked(nsecs_t currentTime, const sp& applicationHandle, - const sp& windowHandle, nsecs_t eventTime, - nsecs_t waitStartTime, const char* reason) REQUIRES(mLock); + void onAnrLocked(const sp& connection) REQUIRES(mLock); + void onAnrLocked(const sp& application) REQUIRES(mLock); + void updateLastAnrStateLocked(const sp& window, const std::string& reason) + REQUIRES(mLock); + void updateLastAnrStateLocked(const sp& application, + const std::string& reason) REQUIRES(mLock); + void updateLastAnrStateLocked(const std::string& windowLabel, const std::string& reason) + REQUIRES(mLock); // Outbound policy interactions. void doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 73d22727f0..a0d2f4f172 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -27,6 +27,7 @@ cc_test { "libinputflinger_defaults", ], srcs: [ + "AnrTracker_test.cpp", "BlockingQueue_test.cpp", "EventHub_test.cpp", "TestInputListener.cpp", diff --git a/services/inputflinger/tests/AnrTracker_test.cpp b/services/inputflinger/tests/AnrTracker_test.cpp new file mode 100644 index 0000000000..b561da107d --- /dev/null +++ b/services/inputflinger/tests/AnrTracker_test.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../AnrTracker.h" + +#include +#include + +namespace android { + +namespace inputdispatcher { + +// --- AnrTrackerTest --- + +/** + * Add a single entry and ensure it's returned as first, even if the token isn't valid + */ +TEST(AnrTrackerTest, SingleEntry_First) { + AnrTracker tracker; + + tracker.insert(1, nullptr); + + ASSERT_EQ(1, tracker.firstTimeout()); + ASSERT_EQ(tracker.firstToken(), nullptr); +} + +TEST(AnrTrackerTest, MultipleEntries_RemoveToken) { + AnrTracker tracker; + + sp token1 = new BBinder(); + sp token2 = new BBinder(); + + tracker.insert(1, token1); + tracker.insert(2, token2); + tracker.insert(3, token1); + tracker.insert(4, token2); + tracker.insert(5, token1); + + tracker.eraseToken(token1); + + ASSERT_EQ(2, tracker.firstTimeout()); +} + +TEST(AnrTrackerTest, AddAndRemove_Empty) { + AnrTracker tracker; + + ASSERT_TRUE(tracker.empty()); + + tracker.insert(1, nullptr); + ASSERT_FALSE(tracker.empty()); + + tracker.erase(1, nullptr); + ASSERT_TRUE(tracker.empty()); +} + +TEST(AnrTrackerTest, Clear) { + AnrTracker tracker; + + tracker.insert(1, nullptr); + tracker.clear(); + ASSERT_TRUE(tracker.empty()); +} + +TEST(AnrTrackerTest, SingleToken_MaintainsOrder) { + AnrTracker tracker; + + ASSERT_TRUE(tracker.empty()); + + tracker.insert(2, nullptr); + tracker.insert(5, nullptr); + tracker.insert(0, nullptr); + + ASSERT_EQ(0, tracker.firstTimeout()); + ASSERT_EQ(nullptr, tracker.firstToken()); +} + +TEST(AnrTrackerTest, MultipleTokens_MaintainsOrder) { + AnrTracker tracker; + + sp token1 = new BBinder(); + sp token2 = new BBinder(); + + tracker.insert(2, token1); + tracker.insert(5, token2); + tracker.insert(0, token2); + + ASSERT_EQ(0, tracker.firstTimeout()); + ASSERT_EQ(token2, tracker.firstToken()); +} + +TEST(AnrTrackerTest, MultipleTokens_IdenticalTimes) { + AnrTracker tracker; + + sp token1 = new BBinder(); + sp token2 = new BBinder(); + + tracker.insert(2, token1); + tracker.insert(2, token2); + tracker.insert(10, token2); + + ASSERT_EQ(2, tracker.firstTimeout()); + // Doesn't matter which token is returned - both are valid results + ASSERT_TRUE(token1 == tracker.firstToken() || token2 == tracker.firstToken()); +} + +TEST(AnrTrackerTest, MultipleTokens_IdenticalTimesRemove) { + AnrTracker tracker; + + sp token1 = new BBinder(); + sp token2 = new BBinder(); + + tracker.insert(2, token1); + tracker.insert(2, token2); + tracker.insert(10, token2); + + tracker.erase(2, token2); + + ASSERT_EQ(2, tracker.firstTimeout()); + ASSERT_EQ(token1, tracker.firstToken()); +} + +TEST(AnrTrackerTest, Empty_DoesntCrash) { + AnrTracker tracker; + + ASSERT_TRUE(tracker.empty()); + + ASSERT_EQ(LONG_LONG_MAX, tracker.firstTimeout()); + // Can't call firstToken() if tracker.empty() +} + +TEST(AnrTrackerTest, RemoveInvalidItem_DoesntCrash) { + AnrTracker tracker; + + tracker.insert(1, nullptr); + + // Remove with non-matching timestamp + tracker.erase(2, nullptr); + ASSERT_EQ(1, tracker.firstTimeout()); + ASSERT_EQ(nullptr, tracker.firstToken()); + + // Remove with non-matching token + tracker.erase(1, new BBinder()); + ASSERT_EQ(1, tracker.firstTimeout()); + ASSERT_EQ(nullptr, tracker.firstToken()); + + // Remove with both non-matching + tracker.erase(2, new BBinder()); + ASSERT_EQ(1, tracker.firstTimeout()); + ASSERT_EQ(nullptr, tracker.firstToken()); +} + +} // namespace inputdispatcher + +} // namespace android diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 13e835427f..1a133dc01c 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -126,6 +126,14 @@ public: void assertNotifyAnrWasCalled(std::chrono::nanoseconds timeout, const sp& expectedApplication, const sp& expectedToken) { + std::pair, sp> anrData; + ASSERT_NO_FATAL_FAILURE(anrData = getNotifyAnrData(timeout)); + ASSERT_EQ(expectedApplication, anrData.first); + ASSERT_EQ(expectedToken, anrData.second); + } + + std::pair, sp> getNotifyAnrData( + std::chrono::nanoseconds timeout) { const std::chrono::time_point start = std::chrono::steady_clock::now(); std::unique_lock lock(mLock); std::chrono::duration timeToWait = timeout + 100ms; // provide some slack @@ -136,16 +144,33 @@ public: // before checking if ANR was called. // Since dispatcher is not guaranteed to call notifyAnr right away, we need to provide // it some time to act. 100ms seems reasonable. - mNotifyAnr.wait_for(lock, timeToWait, - [this]() REQUIRES(mLock) { return mNotifyAnrWasCalled; }); + mNotifyAnr.wait_for(lock, timeToWait, [this]() REQUIRES(mLock) { + return !mAnrApplications.empty() && !mAnrWindowTokens.empty(); + }); const std::chrono::duration waited = std::chrono::steady_clock::now() - start; - ASSERT_TRUE(mNotifyAnrWasCalled); + if (mAnrApplications.empty() || mAnrWindowTokens.empty()) { + ADD_FAILURE() << "Did not receive ANR callback"; + } // Ensure that the ANR didn't get raised too early. We can't be too strict here because // the dispatcher started counting before this function was called - ASSERT_TRUE(timeout - 100ms < waited); // check (waited < timeout + 100ms) done by wait_for - mNotifyAnrWasCalled = false; - ASSERT_EQ(expectedApplication, mLastAnrApplication); - ASSERT_EQ(expectedToken, mLastAnrWindowToken); + if (std::chrono::abs(timeout - waited) > 100ms) { + ADD_FAILURE() << "ANR was raised too early or too late. Expected " + << std::chrono::duration_cast(timeout).count() + << "ms, but waited " + << std::chrono::duration_cast(waited).count() + << "ms instead"; + } + std::pair, sp> result = + std::make_pair(mAnrApplications.front(), mAnrWindowTokens.front()); + mAnrApplications.pop(); + mAnrWindowTokens.pop(); + return result; + } + + void assertNotifyAnrWasNotCalled() { + std::scoped_lock lock(mLock); + ASSERT_TRUE(mAnrApplications.empty()); + ASSERT_TRUE(mAnrWindowTokens.empty()); } void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) { @@ -153,6 +178,8 @@ public: mConfig.keyRepeatDelay = delay; } + void setAnrTimeout(std::chrono::nanoseconds timeout) { mAnrTimeout = timeout; } + private: std::mutex mLock; std::unique_ptr mFilteredEvent GUARDED_BY(mLock); @@ -161,9 +188,8 @@ private: std::optional mLastNotifySwitch GUARDED_BY(mLock); // ANR handling - bool mNotifyAnrWasCalled GUARDED_BY(mLock) = false; - sp mLastAnrApplication GUARDED_BY(mLock); - sp mLastAnrWindowToken GUARDED_BY(mLock); + std::queue> mAnrApplications GUARDED_BY(mLock); + std::queue> mAnrWindowTokens GUARDED_BY(mLock); std::condition_variable mNotifyAnr; std::chrono::nanoseconds mAnrTimeout = 0ms; @@ -175,9 +201,8 @@ private: virtual nsecs_t notifyAnr(const sp& application, const sp& windowToken, const std::string&) override { std::scoped_lock lock(mLock); - mLastAnrApplication = application; - mLastAnrWindowToken = windowToken; - mNotifyAnrWasCalled = true; + mAnrApplications.push(application); + mAnrWindowTokens.push(windowToken); mNotifyAnr.notify_all(); return mAnrTimeout.count(); } @@ -643,7 +668,7 @@ public: ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(expectedEventType, event->getType()) - << mName.c_str() << "expected " << inputEventTypeToString(expectedEventType) + << mName.c_str() << " expected " << inputEventTypeToString(expectedEventType) << " event, got " << inputEventTypeToString(event->getType()) << " event"; EXPECT_EQ(expectedDisplayId, event->getDisplayId()); @@ -688,9 +713,24 @@ public: void assertNoEvents() { InputEvent* event = consume(); - ASSERT_EQ(nullptr, event) - << mName.c_str() - << ": should not have received any events, so consume() should return NULL"; + if (event == nullptr) { + return; + } + if (event->getType() == AINPUT_EVENT_TYPE_KEY) { + KeyEvent& keyEvent = static_cast(*event); + ADD_FAILURE() << "Received key event " + << KeyEvent::actionToString(keyEvent.getAction()); + } else if (event->getType() == AINPUT_EVENT_TYPE_MOTION) { + MotionEvent& motionEvent = static_cast(*event); + ADD_FAILURE() << "Received motion event " + << MotionEvent::actionToString(motionEvent.getAction()); + } else if (event->getType() == AINPUT_EVENT_TYPE_FOCUS) { + FocusEvent& focusEvent = static_cast(*event); + ADD_FAILURE() << "Received focus event, hasFocus = " + << (focusEvent.getHasFocus() ? "true" : "false"); + } + FAIL() << mName.c_str() + << ": should not have received any events, so consume() should return NULL"; } sp getToken() { return mConsumer->getChannel()->getConnectionToken(); } @@ -754,6 +794,8 @@ public: mInfo.dispatchingTimeout = timeout.count(); } + void setPaused(bool paused) { mInfo.paused = paused; } + void setFrame(const Rect& frame) { mInfo.frameLeft = frame.left; mInfo.frameTop = frame.top; @@ -775,6 +817,10 @@ public: expectedFlags); } + void consumeKeyUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + consumeEvent(AINPUT_EVENT_TYPE_KEY, AKEY_EVENT_ACTION_UP, expectedDisplayId, expectedFlags); + } + void consumeMotionCancel(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, expectedDisplayId, @@ -826,12 +872,12 @@ public: expectedFlags); } - std::optional receiveEvent() { + std::optional receiveEvent(InputEvent** outEvent = nullptr) { if (mInputReceiver == nullptr) { ADD_FAILURE() << "Invalid receive event on window with no receiver"; return std::nullopt; } - return mInputReceiver->receiveEvent(); + return mInputReceiver->receiveEvent(outEvent); } void finishEvent(uint32_t sequenceNum) { @@ -865,7 +911,9 @@ private: std::atomic FakeWindowHandle::sId{1}; static int32_t injectKey(const sp& dispatcher, int32_t action, int32_t repeatCount, - int32_t displayId = ADISPLAY_ID_NONE) { + int32_t displayId = ADISPLAY_ID_NONE, + int32_t syncMode = INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, + std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT) { KeyEvent event; nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); @@ -875,10 +923,9 @@ static int32_t injectKey(const sp& dispatcher, int32_t action, repeatCount, currentTime, currentTime); // Inject event until dispatch out. - return dispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, - INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); + return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, syncMode, + injectionTimeout, + POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); } static int32_t injectKeyDown(const sp& dispatcher, @@ -886,11 +933,19 @@ static int32_t injectKeyDown(const sp& dispatcher, return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /* repeatCount */ 0, displayId); } +static int32_t injectKeyUp(const sp& dispatcher, + int32_t displayId = ADISPLAY_ID_NONE) { + return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /* repeatCount */ 0, displayId); +} + static int32_t injectMotionEvent( const sp& dispatcher, int32_t action, int32_t source, int32_t displayId, const PointF& position, const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION}) { + AMOTION_EVENT_INVALID_CURSOR_POSITION}, + std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, + int32_t injectionMode = INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, + nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC)) { MotionEvent event; PointerProperties pointerProperties[1]; PointerCoords pointerCoords[1]; @@ -903,7 +958,6 @@ static int32_t injectMotionEvent( pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, position.x); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, position.y); - nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion down event. event.initialize(InputEvent::nextId(), DEVICE_ID, source, displayId, INVALID_HMAC, action, /* actionButton */ 0, @@ -911,14 +965,13 @@ static int32_t injectMotionEvent( /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, /* xScale */ 1, /* yScale */ 1, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0, /* yPrecision */ 0, cursorPosition.x, cursorPosition.y, - currentTime, currentTime, + eventTime, eventTime, /*pointerCount*/ 1, pointerProperties, pointerCoords); // Inject event until dispatch out. - return dispatcher->injectInputEvent( - &event, - INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, - INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); + return dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID, injectionMode, + injectionTimeout, + POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); } static int32_t injectMotionDown(const sp& dispatcher, int32_t source, @@ -1429,6 +1482,10 @@ public: expectedDisplayId, expectedFlags); } + std::optional receiveEvent() { return mInputReceiver->receiveEvent(); } + + void finishEvent(uint32_t consumeSeq) { return mInputReceiver->finishEvent(consumeSeq); } + void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId, expectedFlags); @@ -1507,6 +1564,21 @@ TEST_F(InputDispatcherTest, GestureMonitor_CanPilferAfterWindowIsRemovedMidStrea monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT); } +TEST_F(InputDispatcherTest, UnresponsiveGestureMonitor_GetsAnr) { + FakeMonitorReceiver monitor = + FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); + std::optional consumeSeq = monitor.receiveEvent(); + ASSERT_TRUE(consumeSeq); + + mFakePolicy->assertNotifyAnrWasCalled(DISPATCHING_TIMEOUT, nullptr, monitor.getToken()); + monitor.finishEvent(*consumeSeq); + ASSERT_TRUE(mDispatcher->waitForIdle()); +} + TEST_F(InputDispatcherTest, TestMoveEvent) { sp application = new FakeApplicationHandle(); sp window = @@ -2329,23 +2401,40 @@ protected: } }; +// Send a tap and respond, which should not cause an ANR. +TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) { + tapOnWindow(); + mWindow->consumeMotionDown(); + mWindow->consumeMotionUp(); + ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyAnrWasNotCalled(); +} + +// Send a regular key and respond, which should not cause an ANR. +TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) { + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher)); + mWindow->consumeKeyDown(ADISPLAY_ID_NONE); + ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyAnrWasNotCalled(); +} + // Send an event to the app and have the app not respond right away. -// Make sure that ANR is raised +// When ANR is raised, policy will tell the dispatcher to cancel the events for that window. +// So InputDispatcher will enqueue ACTION_CANCEL event as well. TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); - // Also, overwhelm the socket to make sure ANR starts - for (size_t i = 0; i < 100; i++) { - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {WINDOW_LOCATION.x, WINDOW_LOCATION.y + i}); - } - std::optional sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + + // The remaining lines are not really needed for the test, but kept as a sanity check + mWindow->finishEvent(*sequenceNum); + mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, + ADISPLAY_ID_DEFAULT, 0 /*flags*/); ASSERT_TRUE(mDispatcher->waitForIdle()); } @@ -2355,14 +2444,591 @@ TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) { ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher)); std::optional sequenceNum = mWindow->receiveEvent(); ASSERT_TRUE(sequenceNum); + const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + ASSERT_TRUE(mDispatcher->waitForIdle()); +} + +// We have a focused application, but no focused window +TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { + mWindow->setFocus(false); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mWindow->consumeFocusEvent(false); + + // taps on the window work as normal + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + WINDOW_LOCATION)); + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); + mDispatcher->waitForIdle(); + mFakePolicy->assertNotifyAnrWasNotCalled(); + + // Once a focused event arrives, we get an ANR for this application + // We specify the injection timeout to be smaller than the application timeout, to ensure that + // injection times out (instead of failing). + const int32_t result = + injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT, + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, 10ms); + ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, result); + const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, mApplication, nullptr /*windowToken*/); + ASSERT_TRUE(mDispatcher->waitForIdle()); +} + +// We have a focused application, but no focused window +// If the policy wants to keep waiting on the focused window to be added, make sure +// that this timeout extension is honored and ANR is raised again. +TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_ExtendsAnr) { + mWindow->setFocus(false); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mWindow->consumeFocusEvent(false); + const std::chrono::duration timeout = 5ms; + mFakePolicy->setAnrTimeout(timeout); + + // Once a focused event arrives, we get an ANR for this application + // We specify the injection timeout to be smaller than the application timeout, to ensure that + // injection times out (instead of failing). + const int32_t result = + injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT, + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, 10ms); + ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, result); + const std::chrono::duration appTimeout = + mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(appTimeout, mApplication, nullptr /*windowToken*/); + + // After the extended time has passed, ANR should be raised again + mFakePolicy->assertNotifyAnrWasCalled(timeout, mApplication, nullptr /*windowToken*/); + + // If we stop extending the timeout, dispatcher should go to idle. + // Another ANR may be raised during this time + mFakePolicy->setAnrTimeout(0ms); + ASSERT_TRUE(mDispatcher->waitForIdle()); +} + +// We have a focused application, but no focused window +TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { + mWindow->setFocus(false); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mWindow->consumeFocusEvent(false); + + // Once a focused event arrives, we get an ANR for this application + const int32_t result = + injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT, + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, 10ms); + ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, result); - // Start ANR process by sending a 2nd key, which would trigger the check for whether - // waitQueue is empty - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /* repeatCount */ 1); + const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, mApplication, nullptr /*windowToken*/); + // Future focused events get dropped right away + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, injectKeyDown(mDispatcher)); + ASSERT_TRUE(mDispatcher->waitForIdle()); + mWindow->assertNoEvents(); +} + +/** + * Ensure that the implementation is valid. Since we are using multiset to keep track of the + * ANR timeouts, we are allowing entries with identical timestamps in the same connection. + * If we process 1 of the events, but ANR on the second event with the same timestamp, + * the ANR mechanism should still work. + * + * In this test, we are injecting DOWN and UP events with the same timestamps, and acknowledging the + * DOWN event, while not responding on the second one. + */ +TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) { + nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, + {AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION}, + 500ms, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, currentTime); + + // Now send ACTION_UP, with identical timestamp + injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, + {AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION}, + 500ms, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, currentTime); + + // We have now sent down and up. Let's consume first event and then ANR on the second. + mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); + const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); +} + +// If an app is not responding to a key event, gesture monitors should continue to receive +// new motion events +TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnrOnKey) { + FakeMonitorReceiver monitor = + FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)); + mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyUp(mDispatcher, ADISPLAY_ID_DEFAULT)); + + // Stuck on the ACTION_UP + const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr, mWindow->getToken()); + + // New tap will go to the gesture monitor, but not to the window + tapOnWindow(); + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT); + + mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT); // still the previous motion + mDispatcher->waitForIdle(); + mWindow->assertNoEvents(); + monitor.assertNoEvents(); +} + +// If an app is not responding to a motion event, gesture monitors should continue to receive +// new motion events +TEST_F(InputDispatcherSingleWindowAnr, GestureMonitors_ReceiveEventsDuringAppAnrOnMotion) { + FakeMonitorReceiver monitor = + FakeMonitorReceiver(mDispatcher, "Gesture monitor", ADISPLAY_ID_DEFAULT, + true /*isGestureMonitor*/); + + tapOnWindow(); + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT); + + mWindow->consumeMotionDown(); + // Stuck on the ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyAnrWasCalled(timeout, mApplication, mWindow->getToken()); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr, mWindow->getToken()); + + // New tap will go to the gesture monitor, but not to the window + tapOnWindow(); + monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); + monitor.consumeMotionUp(ADISPLAY_ID_DEFAULT); + + mWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); // still the previous motion + mDispatcher->waitForIdle(); + mWindow->assertNoEvents(); + monitor.assertNoEvents(); +} + +// If a window is unresponsive, then you get anr. if the window later catches up and starts to +// process events, you don't get an anr. When the window later becomes unresponsive again, you +// get an ANR again. +// 1. tap -> block on ACTION_UP -> receive ANR +// 2. consume all pending events (= queue becomes healthy again) +// 3. tap again -> block on ACTION_UP again -> receive ANR second time +TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) { + tapOnWindow(); + + mWindow->consumeMotionDown(); + // Block on ACTION_UP + const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mWindow->consumeMotionUp(); // Now the connection should be healthy again + mDispatcher->waitForIdle(); + mWindow->assertNoEvents(); + + tapOnWindow(); + mWindow->consumeMotionDown(); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mWindow->consumeMotionUp(); + + mDispatcher->waitForIdle(); + mWindow->assertNoEvents(); +} + +// If the policy tells us to raise ANR again after some time, ensure that the timeout extension +// is honored +TEST_F(InputDispatcherSingleWindowAnr, Policy_CanExtendTimeout) { + const std::chrono::duration timeout = 5ms; + mFakePolicy->setAnrTimeout(timeout); + + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + WINDOW_LOCATION)); + + const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(windowTimeout, nullptr /*application*/, + mWindow->getToken()); + + // Since the policy wanted to extend ANR, make sure it is called again after the extension + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, mWindow->getToken()); + mFakePolicy->setAnrTimeout(0ms); + std::this_thread::sleep_for(windowTimeout); + // We are not checking if ANR has been called, because it may have been called again by the + // time we set the timeout to 0 + + // When the policy finally says stop, we should get ACTION_CANCEL + mWindow->consumeMotionDown(); + mWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, + ADISPLAY_ID_DEFAULT, 0 /*flags*/); + mWindow->assertNoEvents(); +} + +/** + * If a window is processing a motion event, and then a key event comes in, the key event should + * not to to the focused window until the motion is processed. + * + * Warning!!! + * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT + * and the injection timeout that we specify when injecting the key. + * We must have the injection timeout (10ms) be smaller than + * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). + * + * If that value changes, this test should also change. + */ +TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { + mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + + tapOnWindow(); + std::optional downSequenceNum = mWindow->receiveEvent(); + ASSERT_TRUE(downSequenceNum); + std::optional upSequenceNum = mWindow->receiveEvent(); + ASSERT_TRUE(upSequenceNum); + // Don't finish the events yet, and send a key + // Injection will "succeed" because we will eventually give up and send the key to the focused + // window even if motions are still being processed. But because the injection timeout is short, + // we will receive INJECTION_TIMED_OUT as the result. + + int32_t result = + injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT, + INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, 10ms); + ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, result); + // Key will not be sent to the window, yet, because the window is still processing events + // and the key remains pending, waiting for the touch events to be processed + std::optional keySequenceNum = mWindow->receiveEvent(); + ASSERT_FALSE(keySequenceNum); + + std::this_thread::sleep_for(500ms); + // if we wait long enough though, dispatcher will give up, and still send the key + // to the focused window, even though we have not yet finished the motion event + mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); + mWindow->finishEvent(*downSequenceNum); + mWindow->finishEvent(*upSequenceNum); +} + +/** + * If a window is processing a motion event, and then a key event comes in, the key event should + * not go to the focused window until the motion is processed. + * If then a new motion comes in, then the pending key event should be going to the currently + * focused window right away. + */ +TEST_F(InputDispatcherSingleWindowAnr, + PendingKey_IsDroppedWhileMotionIsProcessedAndNewTouchComesIn) { + mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + + tapOnWindow(); + std::optional downSequenceNum = mWindow->receiveEvent(); + ASSERT_TRUE(downSequenceNum); + std::optional upSequenceNum = mWindow->receiveEvent(); + ASSERT_TRUE(upSequenceNum); + // Don't finish the events yet, and send a key + // Injection is async, so it will succeed + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, + ADISPLAY_ID_DEFAULT, INPUT_EVENT_INJECTION_SYNC_NONE)); + // At this point, key is still pending, and should not be sent to the application yet. + std::optional keySequenceNum = mWindow->receiveEvent(); + ASSERT_FALSE(keySequenceNum); + + // Now tap down again. It should cause the pending key to go to the focused window right away. + tapOnWindow(); + mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); // it doesn't matter that we haven't ack'd + // the other events yet. We can finish events in any order. + mWindow->finishEvent(*downSequenceNum); // first tap's ACTION_DOWN + mWindow->finishEvent(*upSequenceNum); // first tap's ACTION_UP + mWindow->consumeMotionDown(); + mWindow->consumeMotionUp(); + mWindow->assertNoEvents(); +} + +class InputDispatcherMultiWindowAnr : public InputDispatcherTest { + virtual void SetUp() override { + InputDispatcherTest::SetUp(); + + mApplication = new FakeApplicationHandle(); + mApplication->setDispatchingTimeout(10ms); + mUnfocusedWindow = + new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT); + mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); + // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this + // window. + // Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped + mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | + InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH | + InputWindowInfo::FLAG_SPLIT_TOUCH); + + mFocusedWindow = + new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); + mFocusedWindow->setDispatchingTimeout(10ms); + mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); + mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL | + InputWindowInfo::FLAG_SPLIT_TOUCH); + + // Set focused application. + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); + mFocusedWindow->setFocus(true); + + // Expect one focus window exist in display. + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); + mFocusedWindow->consumeFocusEvent(true); + } + + virtual void TearDown() override { + InputDispatcherTest::TearDown(); + + mUnfocusedWindow.clear(); + mFocusedWindow.clear(); + } + +protected: + sp mApplication; + sp mUnfocusedWindow; + sp mFocusedWindow; + static constexpr PointF UNFOCUSED_WINDOW_LOCATION = {20, 20}; + static constexpr PointF FOCUSED_WINDOW_LOCATION = {75, 75}; + static constexpr PointF LOCATION_OUTSIDE_ALL_WINDOWS = {40, 40}; + + void tapOnFocusedWindow() { tap(FOCUSED_WINDOW_LOCATION); } + + void tapOnUnfocusedWindow() { tap(UNFOCUSED_WINDOW_LOCATION); } + +private: + void tap(const PointF& location) { + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + location)); + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + location)); + } +}; + +// If we have 2 windows that are both unresponsive, the one with the shortest timeout +// should be ANR'd first. +TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + FOCUSED_WINDOW_LOCATION)) + << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED"; + mFocusedWindow->consumeMotionDown(); + mUnfocusedWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_OUTSIDE, + ADISPLAY_ID_DEFAULT, 0 /*flags*/); + // We consumed all events, so no ANR + ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyAnrWasNotCalled(); + + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + FOCUSED_WINDOW_LOCATION)); + std::optional unfocusedSequenceNum = mUnfocusedWindow->receiveEvent(); + ASSERT_TRUE(unfocusedSequenceNum); + std::optional focusedSequenceNum = mFocusedWindow->receiveEvent(); + ASSERT_TRUE(focusedSequenceNum); + + const std::chrono::duration timeout = + mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, + mFocusedWindow->getToken()); + + mFocusedWindow->finishEvent(*focusedSequenceNum); + mUnfocusedWindow->finishEvent(*unfocusedSequenceNum); + ASSERT_TRUE(mDispatcher->waitForIdle()); +} + +// If we have 2 windows with identical timeouts that are both unresponsive, +// it doesn't matter which order they should have ANR. +// But we should receive ANR for both. +TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) { + // Set the timeout for unfocused window to match the focused window + mUnfocusedWindow->setDispatchingTimeout(10ms); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); + + tapOnFocusedWindow(); + // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window + std::pair, sp> anrData1 = + mFakePolicy->getNotifyAnrData(10ms); + std::pair, sp> anrData2 = + mFakePolicy->getNotifyAnrData(0ms); + + // We don't know which window will ANR first. But both of them should happen eventually. + ASSERT_TRUE(mFocusedWindow->getToken() == anrData1.second || + mFocusedWindow->getToken() == anrData2.second); + ASSERT_TRUE(mUnfocusedWindow->getToken() == anrData1.second || + mUnfocusedWindow->getToken() == anrData2.second); + + ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyAnrWasNotCalled(); +} + +// If a window is already not responding, the second tap on the same window should be ignored. +// We should also log an error to account for the dropped event (not tested here). +// At the same time, FLAG_WATCH_OUTSIDE_TOUCH targets should not receive any events. +TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { + tapOnFocusedWindow(); + mUnfocusedWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_OUTSIDE, + ADISPLAY_ID_DEFAULT, 0 /*flags*/); + // Receive the events, but don't respond + std::optional downEventSequenceNum = mFocusedWindow->receiveEvent(); // ACTION_DOWN + ASSERT_TRUE(downEventSequenceNum); + std::optional upEventSequenceNum = mFocusedWindow->receiveEvent(); // ACTION_UP + ASSERT_TRUE(upEventSequenceNum); + const std::chrono::duration timeout = + mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, + mFocusedWindow->getToken()); + + // Tap once again + // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + FOCUSED_WINDOW_LOCATION)); + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + FOCUSED_WINDOW_LOCATION)); + // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a + // valid touch target + mUnfocusedWindow->assertNoEvents(); + + // Consume the first tap + mFocusedWindow->finishEvent(*downEventSequenceNum); + mFocusedWindow->finishEvent(*upEventSequenceNum); + ASSERT_TRUE(mDispatcher->waitForIdle()); + // The second tap did not go to the focused window + mFocusedWindow->assertNoEvents(); + // should not have another ANR after the window just became healthy again + mFakePolicy->assertNotifyAnrWasNotCalled(); +} + +// If you tap outside of all windows, there will not be ANR +TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) { + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + LOCATION_OUTSIDE_ALL_WINDOWS)); + ASSERT_TRUE(mDispatcher->waitForIdle()); + mFakePolicy->assertNotifyAnrWasNotCalled(); +} + +// Since the focused window is paused, tapping on it should not produce any events +TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { + mFocusedWindow->setPaused(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); + + ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + FOCUSED_WINDOW_LOCATION)); + + std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT)); + ASSERT_TRUE(mDispatcher->waitForIdle()); + // Should not ANR because the window is paused, and touches shouldn't go to it + mFakePolicy->assertNotifyAnrWasNotCalled(); + + mFocusedWindow->assertNoEvents(); + mUnfocusedWindow->assertNoEvents(); +} + +/** + * If a window is processing a motion event, and then a key event comes in, the key event should + * not to to the focused window until the motion is processed. + * If a different window becomes focused at this time, the key should go to that window instead. + * + * Warning!!! + * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT + * and the injection timeout that we specify when injecting the key. + * We must have the injection timeout (10ms) be smaller than + * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). + * + * If that value changes, this test should also change. + */ +TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { + // Set a long ANR timeout to prevent it from triggering + mFocusedWindow->setDispatchingTimeout(2s); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}}); + + tapOnUnfocusedWindow(); + std::optional downSequenceNum = mUnfocusedWindow->receiveEvent(); + ASSERT_TRUE(downSequenceNum); + std::optional upSequenceNum = mUnfocusedWindow->receiveEvent(); + ASSERT_TRUE(upSequenceNum); + // Don't finish the events yet, and send a key + // Injection will succeed because we will eventually give up and send the key to the focused + // window even if motions are still being processed. + + int32_t result = + injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT, + INPUT_EVENT_INJECTION_SYNC_NONE, 10ms /*injectionTimeout*/); + ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, result); + // Key will not be sent to the window, yet, because the window is still processing events + // and the key remains pending, waiting for the touch events to be processed + std::optional keySequenceNum = mFocusedWindow->receiveEvent(); + ASSERT_FALSE(keySequenceNum); + + // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there + mFocusedWindow->setFocus(false); + mUnfocusedWindow->setFocus(true); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}}); + + // Focus events should precede the key events + mUnfocusedWindow->consumeFocusEvent(true); + mFocusedWindow->consumeFocusEvent(false); + + // Finish the tap events, which should unblock dispatcher + mUnfocusedWindow->finishEvent(*downSequenceNum); + mUnfocusedWindow->finishEvent(*upSequenceNum); + + // Now that all queues are cleared and no backlog in the connections, the key event + // can finally go to the newly focused "mUnfocusedWindow". + mUnfocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); + mFocusedWindow->assertNoEvents(); + mUnfocusedWindow->assertNoEvents(); +} + +// When the touch stream is split across 2 windows, and one of them does not respond, +// then ANR should be raised and the touch should be canceled for the unresponsive window. +// The other window should not be affected by that. +TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { + // Touch Window 1 + NotifyMotionArgs motionArgs = + generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {FOCUSED_WINDOW_LOCATION}); + mDispatcher->notifyMotion(&motionArgs); + mUnfocusedWindow->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_OUTSIDE, + ADISPLAY_ID_DEFAULT, 0 /*flags*/); + + // Touch Window 2 + int32_t actionPointerDown = + AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + + motionArgs = + generateMotionArgs(actionPointerDown, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}); + mDispatcher->notifyMotion(&motionArgs); + + const std::chrono::duration timeout = + mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); + mFakePolicy->assertNotifyAnrWasCalled(timeout, nullptr /*application*/, + mFocusedWindow->getToken()); + + mUnfocusedWindow->consumeMotionDown(); + mFocusedWindow->consumeMotionDown(); + // Focused window may or may not receive ACTION_MOVE + // But it should definitely receive ACTION_CANCEL due to the ANR + InputEvent* event; + std::optional moveOrCancelSequenceNum = mFocusedWindow->receiveEvent(&event); + ASSERT_TRUE(moveOrCancelSequenceNum); + mFocusedWindow->finishEvent(*moveOrCancelSequenceNum); + ASSERT_NE(nullptr, event); + ASSERT_EQ(event->getType(), AINPUT_EVENT_TYPE_MOTION); + MotionEvent& motionEvent = static_cast(*event); + if (motionEvent.getAction() == AMOTION_EVENT_ACTION_MOVE) { + mFocusedWindow->consumeMotionCancel(); + } else { + ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionEvent.getAction()); + } + ASSERT_TRUE(mDispatcher->waitForIdle()); + mUnfocusedWindow->assertNoEvents(); + mFocusedWindow->assertNoEvents(); } } // namespace android::inputdispatcher -- cgit v1.2.3-59-g8ed1b From bf1349c867de1813a8002489fe2a5f5cc958ae17 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 12 Jun 2020 14:26:18 -0700 Subject: SurfaceFlinger: add explicit eEarlyWakeup start and end The current handling of eEarlyWakeup is using 2 frames of timeout in SurfaceFlinger to know when we are no longer in early offset config. There are few cases where a transaction is dropped or delayed (usually caused by the offset change itself) which results in switching back and forth from early offset to non-early offset. This change adds two new flags, eExplicitEarlyWakeupStart and eExplicitEarlyWakeupEnd that will be used by WindowManager to indicate when to enter early offset and when to exit. With these explicit flags, the timings on transaction no longer matters and we consistently stay at early offset config for the desired duration. Bug: 158127834 Test: Quick switch between apps and verify that offset doesn't change Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Change-Id: Ie10af30a2d8c0f4f21ac7ffed469a74e1bf8dbc1 --- libs/gui/SurfaceComposerClient.cpp | 31 +++ libs/gui/include/gui/ISurfaceComposer.h | 20 +- libs/gui/include/gui/SurfaceComposerClient.h | 12 +- services/surfaceflinger/Scheduler/Scheduler.h | 17 +- .../surfaceflinger/Scheduler/VSyncModulator.cpp | 46 +++- services/surfaceflinger/Scheduler/VSyncModulator.h | 11 +- services/surfaceflinger/SurfaceFlinger.cpp | 36 ++- services/surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/VSyncModulatorTest.cpp | 301 +++++++++++++++++++++ 9 files changed, 442 insertions(+), 33 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp (limited to 'libs') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5922f3a876..83bc06997a 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -353,6 +353,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), + mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart), + mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd), mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; @@ -375,6 +377,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const uint32_t transactionNestCount = parcel->readUint32(); const bool animation = parcel->readBool(); const bool earlyWakeup = parcel->readBool(); + const bool explicitEarlyWakeupStart = parcel->readBool(); + const bool explicitEarlyWakeupEnd = parcel->readBool(); const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); @@ -443,6 +447,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mTransactionNestCount = transactionNestCount; mAnimation = animation; mEarlyWakeup = earlyWakeup; + mExplicitEarlyWakeupStart = explicitEarlyWakeupStart; + mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd; mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mDisplayStates = displayStates; @@ -470,6 +476,8 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeUint32(mTransactionNestCount); parcel->writeBool(mAnimation); parcel->writeBool(mEarlyWakeup); + parcel->writeBool(mExplicitEarlyWakeupStart); + parcel->writeBool(mExplicitEarlyWakeupEnd); parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeUint32(static_cast(mDisplayStates.size())); @@ -545,6 +553,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mContainsBuffer |= other.mContainsBuffer; mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; + mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart; + mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; other.clear(); return *this; } @@ -559,6 +569,8 @@ void SurfaceComposerClient::Transaction::clear() { mTransactionNestCount = 0; mAnimation = false; mEarlyWakeup = false; + mExplicitEarlyWakeupStart = false; + mExplicitEarlyWakeupEnd = false; mDesiredPresentTime = -1; } @@ -682,9 +694,20 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { flags |= ISurfaceComposer::eEarlyWakeup; } + // If both mExplicitEarlyWakeupStart and mExplicitEarlyWakeupEnd are set + // it is equivalent for none + if (mExplicitEarlyWakeupStart && !mExplicitEarlyWakeupEnd) { + flags |= ISurfaceComposer::eExplicitEarlyWakeupStart; + } + if (mExplicitEarlyWakeupEnd && !mExplicitEarlyWakeupStart) { + flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd; + } + mForceSynchronous = false; mAnimation = false; mEarlyWakeup = false; + mExplicitEarlyWakeupStart = false; + mExplicitEarlyWakeupEnd = false; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, @@ -731,6 +754,14 @@ void SurfaceComposerClient::Transaction::setEarlyWakeup() { mEarlyWakeup = true; } +void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupStart() { + mExplicitEarlyWakeupStart = true; +} + +void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupEnd() { + mExplicitEarlyWakeupEnd = true; +} + layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& handle) { if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b49fa1baf1..8d3160a815 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -81,12 +81,20 @@ public: // flags for setTransactionState() enum { eSynchronous = 0x01, - eAnimation = 0x02, - - // Indicates that this transaction will likely result in a lot of layers being composed, and - // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this - // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns) - eEarlyWakeup = 0x04 + eAnimation = 0x02, + + // DEPRECATED - use eExplicitEarlyWakeup[Start|End] + eEarlyWakeup = 0x04, + + // Explicit indication that this transaction and others to follow will likely result in a + // lot of layers being composed, and thus, SurfaceFlinger should wake-up earlier to avoid + // missing frame deadlines. In this case SurfaceFlinger will wake up at + // (sf vsync offset - debug.sf.early_phase_offset_ns). SurfaceFlinger will continue to be + // in the early configuration until it receives eExplicitEarlyWakeupEnd. These flags are + // expected to be used by WindowManager only and are guarded by + // android.permission.ACCESS_SURFACE_FLINGER + eExplicitEarlyWakeupStart = 0x08, + eExplicitEarlyWakeupEnd = 0x10, }; enum VsyncSource { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index e981a39edc..adcb8982a0 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -345,10 +345,12 @@ public: std::unordered_map, CallbackInfo, TCLHash> mListenerCallbacks; - uint32_t mForceSynchronous = 0; - uint32_t mTransactionNestCount = 0; - bool mAnimation = false; - bool mEarlyWakeup = false; + uint32_t mForceSynchronous = 0; + uint32_t mTransactionNestCount = 0; + bool mAnimation = false; + bool mEarlyWakeup = false; + bool mExplicitEarlyWakeupStart = false; + bool mExplicitEarlyWakeupEnd = false; // Indicates that the Transaction contains a buffer that should be cached bool mContainsBuffer = false; @@ -547,6 +549,8 @@ public: void setDisplaySize(const sp& token, uint32_t width, uint32_t height); void setAnimationTransaction(); void setEarlyWakeup(); + void setExplicitEarlyWakeupStart(); + void setExplicitEarlyWakeupEnd(); }; status_t clearLayerFrameStats(const sp& token) const; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 9e24f90933..730ea8f0c8 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -55,13 +55,24 @@ public: virtual void kernelTimerChanged(bool expired) = 0; }; -class Scheduler { +class IPhaseOffsetControl { +public: + virtual ~IPhaseOffsetControl() = default; + virtual void setPhaseOffset(scheduler::ConnectionHandle, nsecs_t phaseOffset) = 0; +}; + +class Scheduler : public IPhaseOffsetControl { public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; // Indicates whether to start the transaction early, or at vsync time. - enum class TransactionStart { EARLY, NORMAL }; + enum class TransactionStart { + Early, // DEPRECATED. Start the transaction early. Times out on its own + EarlyStart, // Start the transaction early and keep this config until EarlyEnd + EarlyEnd, // End the early config started at EarlyStart + Normal // Start the transaction at the normal time + }; Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, @@ -90,7 +101,7 @@ public: void onScreenReleased(ConnectionHandle); // Modifies phase offset in the event thread. - void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset); + void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset) override; void getDisplayStatInfo(DisplayStatInfo* stats); diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index 510dc2d6ac..2567c0430d 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -31,11 +31,11 @@ namespace android::scheduler { -VSyncModulator::VSyncModulator(Scheduler& scheduler, +VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl, Scheduler::ConnectionHandle appConnectionHandle, Scheduler::ConnectionHandle sfConnectionHandle, const OffsetsConfig& config) - : mScheduler(scheduler), + : mPhaseOffsetControl(phaseOffsetControl), mAppConnectionHandle(appConnectionHandle), mSfConnectionHandle(sfConnectionHandle), mOffsetsConfig(config) { @@ -51,14 +51,35 @@ void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) { } void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { - if (transactionStart == Scheduler::TransactionStart::EARLY) { + switch (transactionStart) { + case Scheduler::TransactionStart::EarlyStart: + ALOGW_IF(mExplicitEarlyWakeup, "Already in TransactionStart::EarlyStart"); + mExplicitEarlyWakeup = true; + break; + case Scheduler::TransactionStart::EarlyEnd: + ALOGW_IF(!mExplicitEarlyWakeup, "Not in TransactionStart::EarlyStart"); + mExplicitEarlyWakeup = false; + break; + case Scheduler::TransactionStart::Normal: + case Scheduler::TransactionStart::Early: + // Non explicit don't change the explicit early wakeup state + break; + } + + if (mTraceDetailedInfo) { + ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup); + } + + if (!mExplicitEarlyWakeup && + (transactionStart == Scheduler::TransactionStart::Early || + transactionStart == Scheduler::TransactionStart::EarlyEnd)) { mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; mEarlyTxnStartTime = std::chrono::steady_clock::now(); } // An early transaction stays an early transaction. if (transactionStart == mTransactionStart || - mTransactionStart == Scheduler::TransactionStart::EARLY) { + mTransactionStart == Scheduler::TransactionStart::EarlyEnd) { return; } mTransactionStart = transactionStart; @@ -67,8 +88,8 @@ void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transaction void VSyncModulator::onTransactionHandled() { mTxnAppliedTime = std::chrono::steady_clock::now(); - if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; - mTransactionStart = Scheduler::TransactionStart::NORMAL; + if (mTransactionStart == Scheduler::TransactionStart::Normal) return; + mTransactionStart = Scheduler::TransactionStart::Normal; updateOffsets(); } @@ -91,11 +112,10 @@ void VSyncModulator::onRefreshRateChangeCompleted() { void VSyncModulator::onRefreshed(bool usedRenderEngine) { bool updateOffsetsNeeded = false; - // Apply a 1ms margin to account for potential data races + // Apply a margin to account for potential data races // This might make us stay in early offsets for one // additional frame but it's better to be conservative here. - static const constexpr std::chrono::nanoseconds kMargin = 1ms; - if ((mEarlyTxnStartTime.load() + kMargin) < mTxnAppliedTime.load()) { + if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) { if (mRemainingEarlyFrameCount > 0) { mRemainingEarlyFrameCount--; updateOffsetsNeeded = true; @@ -121,8 +141,8 @@ VSyncModulator::Offsets VSyncModulator::getOffsets() const { const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. - if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || - mRefreshRateChangePending) { + if (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd || + mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { return mOffsetsConfig.early; } else if (mRemainingRenderEngineUsageCount > 0) { return mOffsetsConfig.earlyGl; @@ -139,8 +159,8 @@ void VSyncModulator::updateOffsets() { void VSyncModulator::updateOffsetsLocked() { const Offsets& offsets = getNextOffsets(); - mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf); - mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app); + mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf); + mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app); mOffsets = offsets; diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index d777ef99ae..ab678c98c5 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -38,6 +38,9 @@ private: // switch in and out of gl composition. static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; + // Margin used to account for potential data races + static const constexpr std::chrono::nanoseconds MARGIN_FOR_TX_APPLY = 1ms; + public: // Wrapper for a collection of surfaceflinger/app offsets for a particular // configuration. @@ -62,7 +65,7 @@ public: bool operator!=(const OffsetsConfig& other) const { return !(*this == other); } }; - VSyncModulator(Scheduler&, ConnectionHandle appConnectionHandle, + VSyncModulator(IPhaseOffsetControl&, ConnectionHandle appConnectionHandle, ConnectionHandle sfConnectionHandle, const OffsetsConfig&); void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex); @@ -91,13 +94,14 @@ public: Offsets getOffsets() const EXCLUDES(mMutex); private: + friend class VSyncModulatorTest; // Returns the next offsets that we should be using const Offsets& getNextOffsets() const REQUIRES(mMutex); // Updates offsets and persists them into the scheduler framework. void updateOffsets() EXCLUDES(mMutex); void updateOffsetsLocked() REQUIRES(mMutex); - Scheduler& mScheduler; + IPhaseOffsetControl& mPhaseOffsetControl; const ConnectionHandle mAppConnectionHandle; const ConnectionHandle mSfConnectionHandle; @@ -107,8 +111,9 @@ private: Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late}; std::atomic mTransactionStart = - Scheduler::TransactionStart::NORMAL; + Scheduler::TransactionStart::Normal; std::atomic mRefreshRateChangePending = false; + std::atomic mExplicitEarlyWakeup = false; std::atomic mRemainingEarlyFrameCount = 0; std::atomic mRemainingRenderEngineUsageCount = 0; std::atomic mEarlyTxnStartTime = {}; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fbfe448cdf..82d8f089ee 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3235,7 +3235,7 @@ uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) { } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) { - return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL); + return setTransactionFlags(flags, Scheduler::TransactionStart::Normal); } uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, @@ -3452,15 +3452,36 @@ void SurfaceFlinger::applyTransactionState( mTraversalNeededMainThread = true; } + const auto transactionStart = [](uint32_t flags) { + if (flags & eEarlyWakeup) { + return Scheduler::TransactionStart::Early; + } + if (flags & eExplicitEarlyWakeupEnd) { + return Scheduler::TransactionStart::EarlyEnd; + } + if (flags & eExplicitEarlyWakeupStart) { + return Scheduler::TransactionStart::EarlyStart; + } + return Scheduler::TransactionStart::Normal; + }(flags); + if (transactionFlags) { if (mInterceptor->isEnabled()) { mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags); } + // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag + if (flags & eEarlyWakeup) { + ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]"); + } + + if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) { + ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags"); + flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd); + } + // this triggers the transaction - const auto start = (flags & eEarlyWakeup) ? Scheduler::TransactionStart::EARLY - : Scheduler::TransactionStart::NORMAL; - setTransactionFlags(transactionFlags, start); + setTransactionFlags(transactionFlags, transactionStart); if (flags & eAnimation) { mAnimTransactionPending = true; @@ -3497,6 +3518,13 @@ void SurfaceFlinger::applyTransactionState( break; } } + } else { + // even if a transaction is not needed, we need to update VsyncModulator + // about explicit early indications + if (transactionStart == Scheduler::TransactionStart::EarlyStart || + transactionStart == Scheduler::TransactionStart::EarlyEnd) { + mVSyncModulator->setTransactionStart(transactionStart); + } } } diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 7574ff1773..3c4a791a5e 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -62,6 +62,7 @@ cc_test { "StrongTypingTest.cpp", "VSyncDispatchTimerQueueTest.cpp", "VSyncDispatchRealtimeTest.cpp", + "VSyncModulatorTest.cpp", "VSyncPredictorTest.cpp", "VSyncReactorTest.cpp", "mock/DisplayHardware/MockComposer.cpp", diff --git a/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp new file mode 100644 index 0000000000..9c1ec07084 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp @@ -0,0 +1,301 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" +#define LOG_NDEBUG 0 + +#include "Scheduler/VSyncModulator.h" + +#include +#include + +using namespace testing; + +namespace android::scheduler { + +class MockScheduler : public IPhaseOffsetControl { +public: + void setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) { + mPhaseOffset[handle] = phaseOffset; + } + + nsecs_t getOffset(ConnectionHandle handle) { return mPhaseOffset[handle]; } + +private: + std::unordered_map mPhaseOffset; +}; + +class VSyncModulatorTest : public testing::Test { +protected: + static constexpr auto MIN_EARLY_FRAME_COUNT_TRANSACTION = + VSyncModulator::MIN_EARLY_FRAME_COUNT_TRANSACTION; + // Add a 1ms slack to avoid strange timer race conditions. + static constexpr auto MARGIN_FOR_TX_APPLY = VSyncModulator::MARGIN_FOR_TX_APPLY + 1ms; + + // Used to enumerate the different offsets we have + enum { + SF_LATE, + APP_LATE, + SF_EARLY, + APP_EARLY, + SF_EARLY_GL, + APP_EARLY_GL, + }; + + std::unique_ptr mVSyncModulator; + MockScheduler mMockScheduler; + ConnectionHandle mAppConnection{1}; + ConnectionHandle mSfConnection{2}; + VSyncModulator::OffsetsConfig mOffsets = {{SF_EARLY, APP_EARLY}, + {SF_EARLY_GL, APP_EARLY_GL}, + {SF_LATE, APP_LATE}}; + + void SetUp() override { + mVSyncModulator = std::make_unique(mMockScheduler, mAppConnection, + mSfConnection, mOffsets); + mVSyncModulator->setPhaseOffsets(mOffsets); + + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); + }; + + void TearDown() override { mVSyncModulator.reset(); } +}; + +TEST_F(VSyncModulatorTest, Normal) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); + } +} + +TEST_F(VSyncModulatorTest, EarlyEnd) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); +} + +TEST_F(VSyncModulatorTest, EarlyStart) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); +} + +TEST_F(VSyncModulatorTest, EarlyStartWithEarly) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Early); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); +} + +TEST_F(VSyncModulatorTest, EarlyStartWithMoreTransactions) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); +} + +TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEnd) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); +} + +TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) { + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd); + std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY); + mVSyncModulator->onTransactionHandled(); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + + for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) { + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection)); + } + + mVSyncModulator->onRefreshed(false); + EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection)); + EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection)); +} + +} // namespace android::scheduler -- cgit v1.2.3-59-g8ed1b From bf601b04404e73071ec872745a8826afb587ea4c Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Thu, 18 Jun 2020 12:30:48 +0000 Subject: use mapRetrieveWO() and retrieveProgram() instead of bpfFdGet() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit straightforward replacement to use new funcs from BpfUtils.h Test: atest libtimeinstate_test - proves it builds, and everything fails like before 'git grep bpf_obj_get_wronly' comes up empty Bug: 150040815 Signed-off-by: Maciej Żenczykowski Original-Change: https://android-review.googlesource.com/1340915 Merged-In: Id2459eca2a66c257e36ffcfb628150da44f90c81 Change-Id: Id2459eca2a66c257e36ffcfb628150da44f90c81 --- libs/cputimeinstate/cputimeinstate.cpp | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'libs') diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 0b77ab31db..50f6289726 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -88,16 +88,6 @@ static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2 return policyN1 - policyN2; } -static int bpf_obj_get_wronly(const char *pathname) { - union bpf_attr attr; - - memset(&attr, 0, sizeof(attr)); - attr.pathname = ptr_to_u64((void *)pathname); - attr.file_flags = BPF_F_WRONLY; - - return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr)); -} - static bool initGlobals() { std::lock_guard guard(gInitializedMutex); if (gInitialized) return true; @@ -156,7 +146,7 @@ static bool initGlobals() { static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) { std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s", eventType.c_str(), eventName.c_str()); - int prog_fd = bpfFdGet(path.c_str(), BPF_F_RDONLY); + int prog_fd = retrieveProgram(path.c_str()); if (prog_fd < 0) return false; return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0; } @@ -183,7 +173,7 @@ bool startTrackingUidTimes() { if (!initGlobals()) return false; if (gTracking) return true; - unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); + unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); if (cpuPolicyFd < 0) return false; for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) { @@ -192,7 +182,7 @@ bool startTrackingUidTimes() { } } - unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); + unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); if (freqToIdxFd < 0) return false; freq_idx_key_t key; for (uint32_t i = 0; i < gNPolicies; ++i) { @@ -207,23 +197,23 @@ bool startTrackingUidTimes() { } } - unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map")); + unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_last_update_map")); if (cpuLastUpdateFd < 0) return false; std::vector zeros(get_nprocs_conf(), 0); uint32_t zero = 0; if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false; - unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map")); + unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_nr_active_map")); if (nrActiveFd < 0) return false; if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false; - unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map")); + unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_nr_active_map")); if (policyNrActiveFd < 0) return false; for (uint32_t i = 0; i < gNPolicies; ++i) { if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false; } - unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map")); + unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map")); if (policyFreqIdxFd < 0) return false; for (uint32_t i = 0; i < gNPolicies; ++i) { auto freqIdx = getPolicyFreqIdx(i); -- cgit v1.2.3-59-g8ed1b From 6b38825494997c3c2ab23e281956bb80558797d7 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 17 Jun 2020 18:47:12 -0700 Subject: Allow native process to load updatable driver. Previously an application process can be specified to load the updatable driver and the driver path will be set up correctly via GraphicsEnvironment.java. For a native process that is not an application process, there's no way for it to be specificed to load the updatable driver and hence the driver path is not set up. This patch provides a way for a native process that runs in an environment, for example shell, where environment variables can be set, to opt into using udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. Bug: b/157832445, b/159240322 Test: ./gapit validate_gpu_profiling --os android Change-Id: I597535caa5ae0a033c2b8d581bb39b14875ac8fc Merged-In: I597535caa5ae0a033c2b8d581bb39b14875ac8fc --- libs/graphicsenv/GraphicsEnv.cpp | 30 ++++++++++++- libs/graphicsenv/IGpuService.cpp | 50 +++++++++++++++++++--- libs/graphicsenv/include/graphicsenv/IGpuService.h | 6 +++ services/gpuservice/GpuService.cpp | 8 ++++ services/gpuservice/GpuService.h | 3 ++ 5 files changed, 89 insertions(+), 8 deletions(-) (limited to 'libs') diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 4809c1f0d8..3d0f8bbb11 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -40,6 +40,13 @@ #include #include +// TODO(b/159240322): Extend this to x86 ABI. +#if defined(__LP64__) +#define UPDATABLE_DRIVER_ABI "arm64-v8a" +#else +#define UPDATABLE_DRIVER_ABI "armeabi-v7a" +#endif // defined(__LP64__) + // TODO(ianelliott@): Get the following from an ANGLE header: #define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting // Version-2 API: @@ -584,7 +591,28 @@ android_namespace_t* GraphicsEnv::getDriverNamespace() { } if (mDriverPath.empty()) { - return nullptr; + // For an application process, driver path is empty means this application is not opted in + // to use updatable driver. Application process doesn't have the ability to set up + // environment variables and hence before `getenv` call will return. + // For a process that is not an application process, if it's run from an environment, + // for example shell, where environment variables can be set, then it can opt into using + // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer + // driver will be used currently. + // TODO(b/159240322) Support the production updatable driver. + const char* id = getenv("UPDATABLE_GFX_DRIVER"); + if (id == nullptr || std::strcmp(id, "1")) { + return nullptr; + } + const sp gpuService = getGpuService(); + if (!gpuService) { + return nullptr; + } + mDriverPath = gpuService->getUpdatableDriverPath(); + if (mDriverPath.empty()) { + return nullptr; + } + mDriverPath.append(UPDATABLE_DRIVER_ABI); + ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str()); } auto vndkNamespace = android_get_exported_namespace("vndk"); diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index de3503bcf0..fa25c5516d 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -27,11 +27,11 @@ class BpGpuService : public BpInterface { public: explicit BpGpuService(const sp& impl) : BpInterface(impl) {} - virtual void setGpuStats(const std::string& driverPackageName, - const std::string& driverVersionName, uint64_t driverVersionCode, - int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GpuStatsInfo::Driver driver, - bool isDriverLoaded, int64_t driverLoadingTime) { + void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, + uint64_t driverVersionCode, int64_t driverBuildTime, + const std::string& appPackageName, const int32_t vulkanVersion, + GpuStatsInfo::Driver driver, bool isDriverLoaded, + int64_t driverLoadingTime) override { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); @@ -48,8 +48,8 @@ public: remote()->transact(BnGpuService::SET_GPU_STATS, data, &reply, IBinder::FLAG_ONEWAY); } - virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, - const GpuStatsInfo::Stats stats, const uint64_t value) { + void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, + const GpuStatsInfo::Stats stats, const uint64_t value) override { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); @@ -60,6 +60,27 @@ public: remote()->transact(BnGpuService::SET_TARGET_STATS, data, &reply, IBinder::FLAG_ONEWAY); } + + void setUpdatableDriverPath(const std::string& driverPath) override { + Parcel data, reply; + data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); + data.writeUtf8AsUtf16(driverPath); + + remote()->transact(BnGpuService::SET_UPDATABLE_DRIVER_PATH, data, &reply, + IBinder::FLAG_ONEWAY); + } + + std::string getUpdatableDriverPath() override { + Parcel data, reply; + data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); + + status_t error = remote()->transact(BnGpuService::GET_UPDATABLE_DRIVER_PATH, data, &reply); + std::string driverPath; + if (error == OK) { + error = reply.readUtf8FromUtf16(&driverPath); + } + return driverPath; + } }; IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService"); @@ -126,6 +147,21 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep return OK; } + case SET_UPDATABLE_DRIVER_PATH: { + CHECK_INTERFACE(IGpuService, data, reply); + + std::string driverPath; + if ((status = data.readUtf8FromUtf16(&driverPath)) != OK) return status; + + setUpdatableDriverPath(driverPath); + return OK; + } + case GET_UPDATABLE_DRIVER_PATH: { + CHECK_INTERFACE(IGpuService, data, reply); + + std::string driverPath = getUpdatableDriverPath(); + return reply->writeUtf8AsUtf16(driverPath); + } case SHELL_COMMAND_TRANSACTION: { int in = data.readFileDescriptor(); int out = data.readFileDescriptor(); diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index c7c6d1e886..2d59fa0165 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -42,6 +42,10 @@ public: // set target stats. virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats, const uint64_t value = 0) = 0; + + // setter and getter for updatable driver path. + virtual void setUpdatableDriverPath(const std::string& driverPath) = 0; + virtual std::string getUpdatableDriverPath() = 0; }; class BnGpuService : public BnInterface { @@ -49,6 +53,8 @@ public: enum IGpuServiceTag { SET_GPU_STATS = IBinder::FIRST_CALL_TRANSACTION, SET_TARGET_STATS, + SET_UPDATABLE_DRIVER_PATH, + GET_UPDATABLE_DRIVER_PATH, // Always append new enum to the end. }; diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index f40ce71bda..304f1d059e 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -62,6 +62,14 @@ void GpuService::setTargetStats(const std::string& appPackageName, const uint64_ mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value); } +void GpuService::setUpdatableDriverPath(const std::string& driverPath) { + developerDriverPath = driverPath; +} + +std::string GpuService::getUpdatableDriverPath() { + return developerDriverPath; +} + status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector& args) { ATRACE_CALL(); diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index b3e34d559e..ba44fe04d4 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -50,6 +50,8 @@ private: int64_t driverLoadingTime) override; void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats, const uint64_t value) override; + void setUpdatableDriverPath(const std::string& driverPath) override; + std::string getUpdatableDriverPath() override; /* * IBinder interface @@ -73,6 +75,7 @@ private: * Attributes */ std::unique_ptr mGpuStats; + std::string developerDriverPath; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From b4a0f8561f198ad71d66367c0b2de0ee1952f259 Mon Sep 17 00:00:00 2001 From: arthurhung Date: Tue, 16 Jun 2020 11:02:50 +0800 Subject: Fix "Allow/Deny" popup window no respond when use cursor Currently all buffered layers will send input info to InputFlinger in order to detect if a window is obsecured by another layer. This could cause the cursor sprite are calculated into the input windows and generate the unexpected FLAG_(PARTIALLY)_OCCLUDED. To fix this, we exclude the cursor layer when fill input info to InputFlinger. Bug: 158717144 Test: atest InputSurfacesTest Test: connect mouse, open camera and popup grant permission dialog Change-Id: Ic57dfc7b68f8bf8fda5d7a77e107ca023b55b891 --- libs/gui/tests/EndToEndNativeInputTest.cpp | 24 ++++++++++++++++++++++++ services/surfaceflinger/BufferLayer.h | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'libs') diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 5188a09c4b..b1d3ecbf36 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -104,6 +104,15 @@ public: return std::make_unique(surfaceControl, width, height); } + static std::unique_ptr makeCursorInputSurface( + const sp &scc, int width, int height) { + sp surfaceControl = + scc->createSurface(String8("Test Cursor Surface"), 0 /* bufHeight */, + 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eCursorWindow); + return std::make_unique(surfaceControl, width, height); + } + InputEvent* consumeEvent() { waitForEventAvailable(); @@ -134,12 +143,14 @@ public: EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction()); EXPECT_EQ(x, mev->getX(0)); EXPECT_EQ(y, mev->getY(0)); + EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); ev = consumeEvent(); ASSERT_NE(ev, nullptr); ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, ev->getType()); mev = static_cast(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction()); + EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); } ~InputSurface() { @@ -537,5 +548,18 @@ TEST_F(InputSurfacesTest, input_respects_outscreen) { injectTap(0, 0); surface->expectTap(1, 1); } + +TEST_F(InputSurfacesTest, input_ignores_cursor_layer) { + std::unique_ptr surface = makeSurface(100, 100); + std::unique_ptr cursorSurface = + InputSurface::makeCursorInputSurface(mComposerClient, 10, 10); + + surface->showAt(10, 10); + surface->assertFocusChange(true); + cursorSurface->showAt(10, 10); + + injectTap(11, 11); + surface->expectTap(1, 1); +} } } diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h index 0e69f60922..26bfb4931b 100644 --- a/services/surfaceflinger/BufferLayer.h +++ b/services/surfaceflinger/BufferLayer.h @@ -148,10 +148,10 @@ private: virtual status_t updateActiveBuffer() = 0; virtual status_t updateFrameNumber(nsecs_t latchTime) = 0; - // We generate InputWindowHandles for all buffered layers regardless of whether they + // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion // detection. - bool needsInputInfo() const override { return true; } + bool needsInputInfo() const override { return !mPotentialCursor; } protected: struct BufferInfo { -- cgit v1.2.3-59-g8ed1b From 74c9cc3112a172d9d637d12e5e257e60c11ba956 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Sat, 20 Jun 2020 03:35:17 -0700 Subject: libgui: align the Surface default mMaxBufferCount value with BufferQueue Bug: 159213110 Bug: 159505775 Test: atest libgui_test:SurfaceTest#DefaultMaxBufferCountSetAndUpdated Change-Id: Ia4f781e0715b3a4e55c598595746bc0d5c76e3ef --- libs/gui/Surface.cpp | 3 ++- libs/gui/tests/Surface_test.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2bf8ff7581..cf269b33ba 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -110,7 +110,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; - mMaxBufferCount = 0; + mMaxBufferCount = NUM_BUFFER_SLOTS; } Surface::~Surface() { @@ -1585,6 +1585,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mStickyTransform = 0; mAutoPrerotation = false; mEnableFrameTimestamps = false; + mMaxBufferCount = NUM_BUFFER_SLOTS; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index c2b4ef93aa..9906166c67 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -1974,4 +1975,29 @@ TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) { ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); } +TEST_F(SurfaceTest, DefaultMaxBufferCountSetAndUpdated) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + + sp surface = new Surface(producer); + sp window(surface); + + int count = -1; + ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count)); + EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count); + + consumer->setMaxBufferCount(10); + ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU)); + EXPECT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count)); + EXPECT_EQ(10, count); + + ASSERT_EQ(NO_ERROR, native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU)); + ASSERT_EQ(NO_ERROR, window->query(window.get(), NATIVE_WINDOW_MAX_BUFFER_COUNT, &count)); + EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From 975cee7270bd708514eac742ca6182b3caaf6962 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 24 Jun 2020 16:10:55 -0700 Subject: adbd_auth: improve logging. Bug: http://b/159061108 Test: treehugger Change-Id: I4aa83e71ea99752dd819a5a5a9d7a050f49c1dae --- libs/adbd_auth/adbd_auth.cpp | 62 +++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'libs') diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp index 5a0d3f6168..458d3fc557 100644 --- a/libs/adbd_auth/adbd_auth.cpp +++ b/libs/adbd_auth/adbd_auth.cpp @@ -83,28 +83,28 @@ public: InitFrameworkHandlers(); epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC)); if (epoll_fd_ == -1) { - PLOG(FATAL) << "failed to create epoll fd"; + PLOG(FATAL) << "adbd_auth: failed to create epoll fd"; } event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); if (event_fd_ == -1) { - PLOG(FATAL) << "failed to create eventfd"; + PLOG(FATAL) << "adbd_auth: failed to create eventfd"; } sock_fd_.reset(android_get_control_socket("adbd")); if (sock_fd_ == -1) { - PLOG(ERROR) << "failed to get adbd authentication socket"; + PLOG(ERROR) << "adbd_auth: failed to get adbd authentication socket"; } else { if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) { - PLOG(FATAL) << "failed to make adbd authentication socket cloexec"; + PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket cloexec"; } if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) { - PLOG(FATAL) << "failed to make adbd authentication socket nonblocking"; + PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket nonblocking"; } if (listen(sock_fd_.get(), 4) != 0) { - PLOG(FATAL) << "failed to listen on adbd authentication socket"; + PLOG(FATAL) << "adbd_auth: failed to listen on adbd authentication socket"; } } } @@ -146,7 +146,7 @@ public: struct epoll_event event; event.events = EPOLLIN; if (!output_queue_.empty()) { - LOG(INFO) << "marking framework writable"; + LOG(INFO) << "adbd_auth: marking framework writable"; event.events |= EPOLLOUT; } event.data.u64 = kEpollConstFramework; @@ -155,7 +155,7 @@ public: } void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) { - LOG(INFO) << "received new framework fd " << new_fd.get() + LOG(INFO) << "adbd_auth: received new framework fd " << new_fd.get() << " (current = " << framework_fd_.get() << ")"; // If we already had a framework fd, clean up after ourselves. @@ -170,7 +170,7 @@ public: struct epoll_event event; event.events = EPOLLIN; if (!output_queue_.empty()) { - LOG(INFO) << "marking framework writable"; + LOG(INFO) << "adbd_auth: marking framework writable"; event.events |= EPOLLOUT; } event.data.u64 = kEpollConstFramework; @@ -180,10 +180,10 @@ public: } void HandlePacket(std::string_view packet) EXCLUDES(mutex_) { - LOG(INFO) << "received packet: " << packet; + LOG(INFO) << "adbd_auth: received packet: " << packet; if (packet.size() < 2) { - LOG(ERROR) << "received packet of invalid length"; + LOG(ERROR) << "adbd_auth: received packet of invalid length"; std::lock_guard lock(mutex_); ReplaceFrameworkFd(unique_fd()); } @@ -197,7 +197,7 @@ public: } } if (!handled_packet) { - LOG(ERROR) << "unhandled packet: " << packet; + LOG(ERROR) << "adbd_auth: unhandled packet: " << packet; std::lock_guard lock(mutex_); ReplaceFrameworkFd(unique_fd()); } @@ -273,14 +273,14 @@ public: iovs[2].iov_base = p->public_key.data(); iovs[2].iov_len = p->public_key.size(); } else { - LOG(FATAL) << "unhandled packet type?"; + LOG(FATAL) << "adbd_auth: unhandled packet type?"; } output_queue_.pop_front(); ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt); if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { - PLOG(ERROR) << "failed to write to framework fd"; + PLOG(ERROR) << "adbd_auth: failed to write to framework fd"; ReplaceFrameworkFd(unique_fd()); return false; } @@ -290,7 +290,7 @@ public: void Run() { if (sock_fd_ == -1) { - LOG(ERROR) << "adbd authentication socket unavailable, disabling user prompts"; + LOG(ERROR) << "adbd_auth: socket unavailable, disabling user prompts"; } else { struct epoll_event event; event.events = EPOLLIN; @@ -309,9 +309,9 @@ public: struct epoll_event events[3]; int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1)); if (rc == -1) { - PLOG(FATAL) << "epoll_wait failed"; + PLOG(FATAL) << "adbd_auth: epoll_wait failed"; } else if (rc == 0) { - LOG(FATAL) << "epoll_wait returned 0"; + LOG(FATAL) << "adbd_auth: epoll_wait returned 0"; } bool restart = false; @@ -326,7 +326,7 @@ public: unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr, SOCK_CLOEXEC | SOCK_NONBLOCK)); if (new_framework_fd == -1) { - PLOG(FATAL) << "failed to accept framework fd"; + PLOG(FATAL) << "adbd_auth: failed to accept framework fd"; } LOG(INFO) << "adbd_auth: received a new framework connection"; @@ -344,7 +344,8 @@ public: uint64_t dummy; int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy))); if (rc != 8) { - PLOG(FATAL) << "failed to read from eventfd (rc = " << rc << ")"; + PLOG(FATAL) + << "adbd_auth: failed to read from eventfd (rc = " << rc << ")"; } std::lock_guard lock(mutex_); @@ -357,9 +358,9 @@ public: if (event.events & EPOLLIN) { int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf))); if (rc == -1) { - LOG(FATAL) << "failed to read from framework fd"; + LOG(FATAL) << "adbd_auth: failed to read from framework fd"; } else if (rc == 0) { - LOG(INFO) << "hit EOF on framework fd"; + LOG(INFO) << "adbd_auth: hit EOF on framework fd"; std::lock_guard lock(mutex_); ReplaceFrameworkFd(unique_fd()); } else { @@ -386,10 +387,10 @@ public: void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) { for (const auto& path : key_paths) { if (access(path, R_OK) == 0) { - LOG(INFO) << "Loading keys from " << path; + LOG(INFO) << "adbd_auth: loading keys from " << path; std::string content; if (!android::base::ReadFileToString(path, &content)) { - PLOG(ERROR) << "Couldn't read " << path; + PLOG(ERROR) << "adbd_auth: couldn't read " << path; continue; } for (const auto& line : android::base::Split(content, "\n")) { @@ -405,6 +406,7 @@ public: uint64_t id = NextId(); std::lock_guard lock(mutex_); + LOG(INFO) << "adbd_auth: sending prompt with id " << id; pending_prompts_.emplace_back(id, public_key, arg); DispatchPendingPrompt(); return id; @@ -423,7 +425,7 @@ public: std::lock_guard lock(mutex_); auto it = keys_.find(id); if (it == keys_.end()) { - LOG(DEBUG) << "couldn't find public key to notify disconnection, skipping"; + LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection, skipping"; return; } output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)}); @@ -446,7 +448,8 @@ public: std::lock_guard lock(mutex_); auto it = keys_.find(id); if (it == keys_.end()) { - LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping"; + LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection of tls " + "device, skipping"; return; } output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{ @@ -461,9 +464,9 @@ public: uint64_t value = 1; ssize_t rc = write(event_fd_.get(), &value, sizeof(value)); if (rc == -1) { - PLOG(FATAL) << "write to eventfd failed"; + PLOG(FATAL) << "adbd_auth: write to eventfd failed"; } else if (rc != sizeof(value)) { - LOG(FATAL) << "write to eventfd returned short (" << rc << ")"; + LOG(FATAL) << "adbd_auth: write to eventfd returned short (" << rc << ")"; } } @@ -516,8 +519,9 @@ AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) { if (callbacks->version == 1) { return new AdbdAuthContext(reinterpret_cast(callbacks)); } else { - LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version; - return nullptr; + LOG(ERROR) << "adbd_auth: received unknown AdbdAuthCallbacks version " + << callbacks->version; + return nullptr; } } -- cgit v1.2.3-59-g8ed1b From 9e933c54793f56a9c66cba353d997a38d5598d9c Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 24 Jun 2020 16:11:21 -0700 Subject: adbd_auth: return auth id when requesting a prompt. When multiple auth requests come in (e.g. if someone connects over TCP and USB, or if we send a USB request, and then kill adb and try again), we need to know the ID assigned to the request to disambiguate. Bug: http://b/159061108 Test: manual Change-Id: I68cf2335c5958decf29e58ed9132735577a7e074 --- libs/adbd_auth/adbd_auth.cpp | 7 ++++++- libs/adbd_auth/include/adbd_auth.h | 20 +++++++++++++++++--- libs/adbd_auth/libadbd_auth.map.txt | 1 + 3 files changed, 24 insertions(+), 4 deletions(-) (limited to 'libs') diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp index 458d3fc557..0e5d474612 100644 --- a/libs/adbd_auth/adbd_auth.cpp +++ b/libs/adbd_auth/adbd_auth.cpp @@ -549,7 +549,12 @@ void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id) { void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* opaque) { - ctx->PromptUser(std::string_view(public_key, len), opaque); + adbd_auth_prompt_user_with_id(ctx, public_key, len, opaque); +} + +uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx, const char* public_key, size_t len, + void* opaque) { + return ctx->PromptUser(std::string_view(public_key, len), opaque); } uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx, diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h index 6ee3166e3a..8f834df62b 100644 --- a/libs/adbd_auth/include/adbd_auth.h +++ b/libs/adbd_auth/include/adbd_auth.h @@ -122,9 +122,23 @@ void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, * @param len the length of the public_key argument * @param arg an opaque userdata argument */ -void adbd_auth_prompt_user(AdbdAuthContext* ctx, - const char* public_key, - size_t len, void* opaque) __INTRODUCED_IN(30); +void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* opaque) + __INTRODUCED_IN(30); + +/** + * Prompt the user to authorize a public key. + * + * When this happens, a callback will be run on the auth thread with the result. + * + * @param ctx the AdbdAuthContext + * @param public_key the RSA public key to prompt user with + * @param len the length of the public_key argument + * @param arg an opaque userdata argument + * @return a unique id which will be returned via callback + */ +__attribute__((weak)) uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx, + const char* public_key, size_t len, + void* opaque) __INTRODUCED_IN(30); /** * Let system_server know that a TLS device has connected. diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt index 5857ecb98e..7584ca3f53 100644 --- a/libs/adbd_auth/libadbd_auth.map.txt +++ b/libs/adbd_auth/libadbd_auth.map.txt @@ -7,6 +7,7 @@ LIBADBD_AUTH { adbd_auth_notify_auth; # apex introduced=30 adbd_auth_notify_disconnect; # apex introduced=30 adbd_auth_prompt_user; # apex introduced=30 + adbd_auth_prompt_user_with_id; # apex introduced=30 adbd_auth_tls_device_connected; # apex introduced=30 adbd_auth_tls_device_disconnected; # apex introduced=30 adbd_auth_get_max_version; # apex introduced=30 -- cgit v1.2.3-59-g8ed1b From 9653c9cf610ba5c241b7f29f2ddc2821e41d4d85 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 24 Jun 2020 16:12:30 -0700 Subject: adbd_auth: don't abort on unexpected response. There seems to be an additional underlying bug that causes the framework to send a spurious authentication denial, but this is still an improvement. Bug: http://b/159061108 Test: treehugger Change-Id: I7028292fbde157f02cc35c3a37ab5c49d68eaae6 --- libs/adbd_auth/adbd_auth.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'libs') diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp index 0e5d474612..dae6eebaa5 100644 --- a/libs/adbd_auth/adbd_auth.cpp +++ b/libs/adbd_auth/adbd_auth.cpp @@ -206,12 +206,18 @@ public: void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) { std::lock_guard lock(mutex_); CHECK(buf.empty()); - CHECK(dispatched_prompt_.has_value()); - auto& [id, key, arg] = *dispatched_prompt_; - keys_.emplace(id, std::move(key)); - callbacks_.key_authorized(arg, id); - dispatched_prompt_ = std::nullopt; + if (dispatched_prompt_.has_value()) { + // It's possible for the framework to send us a response without our having sent a + // request to it: e.g. if adbd restarts while we have a pending request. + auto& [id, key, arg] = *dispatched_prompt_; + keys_.emplace(id, std::move(key)); + + callbacks_.key_authorized(arg, id); + dispatched_prompt_ = std::nullopt; + } else { + LOG(WARNING) << "adbd_auth: received authorization for unknown prompt, ignoring"; + } // We need to dispatch pending prompts here upon success as well, // since we might have multiple queued prompts. -- cgit v1.2.3-59-g8ed1b From 3b8e3215a6927724e366702c03be44fffb620b26 Mon Sep 17 00:00:00 2001 From: Victor Khimenko Date: Tue, 16 Jun 2020 01:01:15 +0200 Subject: Make libarect buildable for native_bridge Also make headers available for RenderScript. Bug: http://b/153609531 Test: m libarect.native_bridge Change-Id: Iee387d19d167d8b90f4bf3fae7869ea370025b9a Merged-In: Iee387d19d167d8b90f4bf3fae7869ea370025b9a --- libs/arect/Android.bp | 2 ++ libs/nativebase/Android.bp | 2 ++ libs/nativewindow/Android.bp | 2 ++ 3 files changed, 6 insertions(+) (limited to 'libs') diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index f66673f6ad..258a4e3748 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -29,6 +29,8 @@ cc_library_static { name: "libarect", host_supported: true, vendor_available: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, export_include_dirs: ["include"], target: { windows: { diff --git a/libs/nativebase/Android.bp b/libs/nativebase/Android.bp index 9e7e4a2291..8399e8ce0a 100644 --- a/libs/nativebase/Android.bp +++ b/libs/nativebase/Android.bp @@ -16,6 +16,8 @@ cc_library_headers { name: "libnativebase_headers", vendor_available: true, host_supported: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, export_include_dirs: ["include"], target: { diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index ee006aaaba..52d73e0a56 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -25,6 +25,8 @@ cc_library_headers { name: "libnativewindow_headers", export_include_dirs: ["include"], vendor_available: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, min_sdk_version: "29", } -- cgit v1.2.3-59-g8ed1b From 9a12a013eeca75b2a3bf49492ec6557245a6f8fc Mon Sep 17 00:00:00 2001 From: Victor Khimenko Date: Fri, 3 Jul 2020 00:06:50 +0200 Subject: Make libbinder buildable for native_bridge Bug: http://b/153609531 Test: m libbinder.native_bridge Change-Id: I3955d9b54aaea7a6b5b9bde81a336908a849cde6 Merged-In: I3955d9b54aaea7a6b5b9bde81a336908a849cde6 --- libs/binder/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libs') diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index db4aba8640..b24a577588 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -17,6 +17,8 @@ cc_library_headers { export_include_dirs: ["include"], vendor_available: true, host_supported: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, header_libs: [ "libbase_headers", @@ -62,6 +64,8 @@ cc_library { }, double_loadable: true, host_supported: true, + // TODO(b/153609531): remove when no longer needed. + native_bridge_supported: true, // TODO(b/31559095): get headers from bionic on host include_dirs: [ -- cgit v1.2.3-59-g8ed1b From df8a0739f7ab42ce59e2370867d26ed2793b6228 Mon Sep 17 00:00:00 2001 From: Stan Iliev Date: Thu, 16 Jul 2020 17:09:57 -0400 Subject: Fix TextureView calling eglCreateImage with a destructed buffer Fix an issue with hardware buffer passed from the SurfaceTexture being destroyed before an SkImage is created. This CL is matched by a change in frameworks/base I4d121f087fc842ce317745e7b7e2656f80a52b7d. Test: Ran TextureView CTS tests and a few apps that use TextureView. Test: Fix verified by partner Mediatek Bug: 160930384 Bug: 152781833 Bug: 153045874 Bug: 156047948 Bug: 160514803 Bug: 155545635 Bug: 155171712 Change-Id: I2e025e683052168546f2e271a20a857b1e556b64 (cherry picked from commit 0702f1d077bab79c76a4889d7859abbaabf06b81) --- .../include/surfacetexture/surface_texture_platform.h | 2 ++ libs/nativedisplay/surfacetexture/surface_texture.cpp | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'libs') diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h index e2d036bfb0..f3716674c5 100644 --- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h +++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h @@ -79,6 +79,8 @@ typedef int (*ASurfaceTexture_fenceWait)(int fence, void* fencePassThroughHandle /** * ASurfaceTexture_dequeueBuffer returns the next available AHardwareBuffer. + * The caller gets ownership of the buffer and need to release it with + * AHardwareBuffer_release. */ AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlotid, android_dataspace* outDataspace, diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp index d1bcd8d1b1..ebe4484873 100644 --- a/libs/nativedisplay/surfacetexture/surface_texture.cpp +++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp @@ -208,7 +208,15 @@ AHardwareBuffer* ASurfaceTexture_dequeueBuffer(ASurfaceTexture* st, int* outSlot *outNewContent = true; } } while (buffer.get() && (!queueEmpty)); - return reinterpret_cast(buffer.get()); + AHardwareBuffer* result = nullptr; + if (buffer.get()) { + result = buffer->toAHardwareBuffer(); + // add a reference to keep the hardware buffer alive, even if + // BufferQueueProducer is disconnected. This is needed, because + // sp reference is destroyed at the end of this function. + AHardwareBuffer_acquire(result); + } + return result; } } // namespace android -- cgit v1.2.3-59-g8ed1b