diff options
20 files changed, 492 insertions, 79 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 0e9ce897bc..24b201f8ab 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2418,7 +2418,7 @@ void Dumpstate::DumpstateBoard(int out_fd) { // Given that bugreport is required to diagnose failures, it's better to set an arbitrary amount // of timeout for IDumpstateDevice than to block the rest of bugreport. In the timeout case, we // will kill the HAL and grab whatever it dumped in time. - constexpr size_t timeout_sec = 30; + constexpr size_t timeout_sec = 45; if (dumpstate_hal_handle_aidl != nullptr) { DoDumpstateBoardAidl(dumpstate_hal_handle_aidl, dumpstate_fds, options_->bugreport_mode, diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp index e1cbc1996d..8132d46940 100644 --- a/libs/binder/MemoryHeapBase.cpp +++ b/libs/binder/MemoryHeapBase.cpp @@ -18,10 +18,13 @@ #include <errno.h> #include <fcntl.h> +#include <linux/memfd.h> #include <stdint.h> #include <stdlib.h> #include <sys/ioctl.h> +#include <sys/mman.h> #include <sys/stat.h> +#include <sys/syscall.h> #include <sys/types.h> #include <unistd.h> @@ -34,6 +37,24 @@ namespace android { // --------------------------------------------------------------------------- +#ifdef __BIONIC__ +static int memfd_create_region(const char* name, size_t size) { + int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd == -1) { + ALOGE("%s: memfd_create(%s, %zd) failed: %s\n", __func__, name, size, strerror(errno)); + return -1; + } + + if (ftruncate(fd, size) == -1) { + ALOGE("%s, ftruncate(%s, %zd) failed for memfd creation: %s\n", __func__, name, size, + strerror(errno)); + close(fd); + return -1; + } + return fd; +} +#endif + MemoryHeapBase::MemoryHeapBase() : mFD(-1), mSize(0), mBase(MAP_FAILED), mDevice(nullptr), mNeedUnmap(false), mOffset(0) @@ -45,15 +66,36 @@ MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) mDevice(nullptr), mNeedUnmap(false), mOffset(0) { const size_t pagesize = getpagesize(); - size = ((size + pagesize-1) & ~(pagesize-1)); - int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size); - ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno)); - if (fd >= 0) { - if (mapfd(fd, true, size) == NO_ERROR) { - if (flags & READ_ONLY) { - ashmem_set_prot_region(fd, PROT_READ); - } + size = ((size + pagesize - 1) & ~(pagesize - 1)); + int fd = -1; + if (mFlags & FORCE_MEMFD) { +#ifdef __BIONIC__ + ALOGV("MemoryHeapBase: Attempting to force MemFD"); + fd = memfd_create_region(name ? name : "MemoryHeapBase", size); + if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return; + const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) | + ((mFlags & MEMFD_ALLOW_SEALING) ? 0 : F_SEAL_SEAL); + if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) { + ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error %s", name, + SEAL_FLAGS, strerror(errno)); + munmap(mBase, mSize); + mBase = nullptr; + mSize = 0; + close(fd); } + return; +#else + mFlags &= ~(FORCE_MEMFD | MEMFD_ALLOW_SEALING); +#endif + } + if (mFlags & MEMFD_ALLOW_SEALING) { + LOG_ALWAYS_FATAL("Invalid Flags. MEMFD_ALLOW_SEALING only valid with FORCE_MEMFD."); + } + fd = ashmem_create_region(name ? name : "MemoryHeapBase", size); + ALOGE_IF(fd < 0, "MemoryHeapBase: error creating ashmem region: %s", strerror(errno)); + if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return; + if (mFlags & READ_ONLY) { + ashmem_set_prot_region(fd, PROT_READ); } } @@ -61,6 +103,9 @@ MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags) : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), mDevice(nullptr), mNeedUnmap(false), mOffset(0) { + if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) { + LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor"); + } int open_flags = O_RDWR; if (flags & NO_CACHING) open_flags |= O_SYNC; @@ -80,6 +125,9 @@ MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, off_t offset : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags), mDevice(nullptr), mNeedUnmap(false), mOffset(0) { + if (flags & (FORCE_MEMFD | MEMFD_ALLOW_SEALING)) { + LOG_ALWAYS_FATAL("FORCE_MEMFD, MEMFD_ALLOW_SEALING only valid with creating constructor"); + } const size_t pagesize = getpagesize(); size = ((size + pagesize-1) & ~(pagesize-1)); mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset); diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp index 2e86b7415a..3cf94e3047 100644 --- a/libs/binder/ParcelableHolder.cpp +++ b/libs/binder/ParcelableHolder.cpp @@ -52,7 +52,10 @@ status_t ParcelableHolder::writeToParcel(Parcel* p) const { } status_t ParcelableHolder::readFromParcel(const Parcel* p) { - this->mStability = static_cast<Stability>(p->readInt32()); + int32_t wireStability; + if (status_t status = p->readInt32(&wireStability); status != OK) return status; + if (static_cast<int32_t>(this->mStability) != wireStability) return BAD_VALUE; + this->mParcelable = nullptr; this->mParcelableName = std::nullopt; int32_t rawDataSize; diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index e79cb86ffa..d40778a3d8 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -853,10 +853,16 @@ status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, Co } if (session->mConnections.mOutgoing.size() == 0) { - ALOGE("Session has no client connections. This is required for an RPC server to make " - "any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server " - "connections: %zu", - static_cast<int>(use), session->mConnections.mIncoming.size()); + ALOGE("Session has no outgoing connections. This is required for an RPC server to make " + "any non-nested (e.g. oneway or on another thread) calls. Use code request " + "reason: %d. Incoming connections: %zu. %s.", + static_cast<int>(use), session->mConnections.mIncoming.size(), + (session->server() + ? "This is a server session, so see RpcSession::setMaxIncomingThreads " + "for the corresponding client" + : "This is a client session, so see RpcSession::setMaxOutgoingThreads " + "for this client or RpcServer::setMaxThreads for the corresponding " + "server")); return WOULD_BLOCK; } diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h index dd76943ac7..15dd28f08e 100644 --- a/libs/binder/include/binder/MemoryHeapBase.h +++ b/libs/binder/include/binder/MemoryHeapBase.h @@ -34,7 +34,21 @@ public: // memory won't be mapped locally, but will be mapped in the remote // process. DONT_MAP_LOCALLY = 0x00000100, - NO_CACHING = 0x00000200 + NO_CACHING = 0x00000200, + // Bypass ashmem-libcutils to create a memfd shared region. + // Ashmem-libcutils will eventually migrate to memfd. + // Memfd has security benefits and supports file sealing. + // Calling process will need to modify selinux permissions to + // open access to tmpfs files. See audioserver for examples. + // This is only valid for size constructor. + // For host compilation targets, memfd is stubbed in favor of /tmp + // files so sealing is not enforced. + FORCE_MEMFD = 0x00000400, + // Default opt-out of sealing behavior in memfd to avoid potential DOS. + // Clients of shared files can seal at anytime via syscall, leading to + // TOC/TOU issues if additional seals prevent access from the creating + // process. Alternatively, seccomp fcntl(). + MEMFD_ALLOW_SEALING = 0x00000800 }; /* diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h index 28819bb42a..f45aa7631b 100644 --- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h @@ -101,7 +101,12 @@ class AParcelableHolder { return STATUS_INVALID_OPERATION; } - RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability)); + parcelable_stability_t wireStability; + RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability)); + if (this->mStability != wireStability) { + return STATUS_BAD_VALUE; + } + int32_t dataSize; binder_status_t status = AParcel_readInt32(parcel, &dataSize); diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs index d58e839ad4..432da5dfd7 100644 --- a/libs/binder/rust/src/parcel/parcelable_holder.rs +++ b/libs/binder/rust/src/parcel/parcelable_holder.rs @@ -233,7 +233,9 @@ impl Parcelable for ParcelableHolder { } fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> { - self.stability = parcel.read()?; + if self.stability != parcel.read()? { + return Err(StatusCode::BAD_VALUE); + } let data_size: i32 = parcel.read()?; if data_size < 0 { diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index ff55d6ebdc..a3533d831b 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -99,6 +99,7 @@ cc_test { "binderParcelUnitTest.cpp", "binderBinderUnitTest.cpp", "binderStatusUnitTest.cpp", + "binderMemoryHeapBaseUnitTest.cpp", ], shared_libs: [ "libbinder", diff --git a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp new file mode 100644 index 0000000000..21cb70be17 --- /dev/null +++ b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 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 <binder/MemoryHeapBase.h> +#include <cutils/ashmem.h> +#include <fcntl.h> + +#include <gtest/gtest.h> +using namespace android; +#ifdef __BIONIC__ +TEST(MemoryHeapBase, ForceMemfdRespected) { + auto mHeap = sp<MemoryHeapBase>::make(10, MemoryHeapBase::FORCE_MEMFD, "Test mapping"); + int fd = mHeap->getHeapID(); + EXPECT_NE(fd, -1); + EXPECT_FALSE(ashmem_valid(fd)); + EXPECT_NE(fcntl(fd, F_GET_SEALS), -1); +} + +TEST(MemoryHeapBase, MemfdSealed) { + auto mHeap = sp<MemoryHeapBase>::make(8192, + MemoryHeapBase::FORCE_MEMFD, + "Test mapping"); + int fd = mHeap->getHeapID(); + EXPECT_NE(fd, -1); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL); +} + +TEST(MemoryHeapBase, MemfdUnsealed) { + auto mHeap = sp<MemoryHeapBase>::make(8192, + MemoryHeapBase::FORCE_MEMFD | + MemoryHeapBase::MEMFD_ALLOW_SEALING, + "Test mapping"); + int fd = mHeap->getHeapID(); + EXPECT_NE(fd, -1); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0); +} + +TEST(MemoryHeapBase, MemfdSealedProtected) { + auto mHeap = sp<MemoryHeapBase>::make(8192, + MemoryHeapBase::FORCE_MEMFD | + MemoryHeapBase::READ_ONLY, + "Test mapping"); + int fd = mHeap->getHeapID(); + EXPECT_NE(fd, -1); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE); +} + +TEST(MemoryHeapBase, MemfdUnsealedProtected) { + auto mHeap = sp<MemoryHeapBase>::make(8192, + MemoryHeapBase::FORCE_MEMFD | + MemoryHeapBase::READ_ONLY | + MemoryHeapBase::MEMFD_ALLOW_SEALING, + "Test mapping"); + int fd = mHeap->getHeapID(); + EXPECT_NE(fd, -1); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE); +} + +#else +TEST(MemoryHeapBase, HostMemfdExpected) { + auto mHeap = sp<MemoryHeapBase>::make(8192, + MemoryHeapBase::READ_ONLY, + "Test mapping"); + int fd = mHeap->getHeapID(); + void* ptr = mHeap->getBase(); + EXPECT_NE(ptr, MAP_FAILED); + EXPECT_TRUE(ashmem_valid(fd)); + EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY); +} + +TEST(MemoryHeapBase,HostMemfdException) { + auto mHeap = sp<MemoryHeapBase>::make(8192, + MemoryHeapBase::FORCE_MEMFD | + MemoryHeapBase::READ_ONLY | + MemoryHeapBase::MEMFD_ALLOW_SEALING, + "Test mapping"); + int fd = mHeap->getHeapID(); + void* ptr = mHeap->getBase(); + EXPECT_EQ(mHeap->getFlags(), MemoryHeapBase::READ_ONLY); + EXPECT_TRUE(ashmem_valid(fd)); + EXPECT_NE(ptr, MAP_FAILED); +} + +#endif diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index 38bde3a011..57d496d2fb 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -66,10 +66,13 @@ cc_library_static { srcs: [ "random_fd.cpp", "random_parcel.cpp", + "libbinder_driver.cpp", + "libbinder_ndk_driver.cpp", ], shared_libs: [ "libbase", "libbinder", + "libbinder_ndk", "libcutils", "libutils", ], diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h new file mode 100644 index 0000000000..a9a6197439 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <binder/IBinder.h> +#include <fuzzer/FuzzedDataProvider.h> + +namespace android { +/** + * Based on the random data in provider, construct an arbitrary number of + * Parcel objects and send them to the service in serial. + * + * Usage: + * + * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + * FuzzedDataProvider provider = FuzzedDataProvider(data, size); + * // can use provider here to create a service with different options + * sp<IFoo> myService = sp<IFoo>::make(...); + * fuzzService(myService, std::move(provider)); + * } + */ +void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider); +} // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h new file mode 100644 index 0000000000..f2b782337c --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/binder_parcel.h> +#include <fuzzer/FuzzedDataProvider.h> + +namespace android { +/** + * Based on the random data in provider, construct an arbitrary number of + * Parcel objects and send them to the service in serial. + * + * Usage: + * + * extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + * FuzzedDataProvider provider = FuzzedDataProvider(data, size); + * // can use provider here to create a service with different options + * std::shared_ptr<IFoo> myService = ndk::SharedRefBase<IFoo>::make(...); + * fuzzService(myService->asBinder().get(), std::move(provider)); + * } + */ +void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider); +} // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp new file mode 100644 index 0000000000..e849c9bbce --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <fuzzbinder/libbinder_driver.h> + +#include <fuzzbinder/random_parcel.h> + +namespace android { + +void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) { + while (provider.remaining_bytes() > 0) { + uint32_t code = provider.ConsumeIntegral<uint32_t>(); + uint32_t flags = provider.ConsumeIntegral<uint32_t>(); + Parcel data; + + std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>( + provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes())); + fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size())); + + Parcel reply; + (void)binder->transact(code, data, &reply, flags); + } +} + +} // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp new file mode 100644 index 0000000000..462ef9a5e9 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <fuzzbinder/libbinder_ndk_driver.h> + +#include <fuzzbinder/libbinder_driver.h> +#include <fuzzbinder/random_parcel.h> + +// libbinder_ndk doesn't export this header which breaks down its API for NDK +// and APEX users, but we need access to it to fuzz. +#include "../../ndk/ibinder_internal.h" + +namespace android { + +void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) { + fuzzService(binder->getBinder(), std::move(provider)); +} + +} // namespace android diff --git a/libs/input/Android.bp b/libs/input/Android.bp index e73c3b8518..71a129141d 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -113,7 +113,7 @@ cc_library { "frameworks/native/libs/arect/include", ], }, - linux_glibc: { + host_linux: { srcs: [ "InputTransport.cpp", "android/os/IInputConstants.aidl", diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index cf774fd9b8..0c5d61b8d5 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -624,8 +624,10 @@ void CreateInfoWrapper::FilterExtension(const char* name) { switch (ext_bit) { case ProcHook::KHR_android_surface: case ProcHook::KHR_surface: + case ProcHook::KHR_surface_protected_capabilities: case ProcHook::EXT_swapchain_colorspace: case ProcHook::KHR_get_surface_capabilities2: + case ProcHook::GOOGLE_surfaceless_query: hook_extensions_.set(ext_bit); // return now as these extensions do not require HAL support return; @@ -701,8 +703,10 @@ void CreateInfoWrapper::FilterExtension(const char* name) { case ProcHook::KHR_external_fence_capabilities: case ProcHook::KHR_get_surface_capabilities2: case ProcHook::KHR_surface: + case ProcHook::KHR_surface_protected_capabilities: case ProcHook::EXT_debug_report: case ProcHook::EXT_swapchain_colorspace: + case ProcHook::GOOGLE_surfaceless_query: case ProcHook::ANDROID_native_buffer: case ProcHook::EXTENSION_CORE_1_0: case ProcHook::EXTENSION_CORE_1_1: @@ -913,6 +917,9 @@ VkResult EnumerateInstanceExtensionProperties( loader_extensions.push_back({ VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION}); + loader_extensions.push_back( + {VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME, + VK_KHR_SURFACE_PROTECTED_CAPABILITIES_SPEC_VERSION}); loader_extensions.push_back({ VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_SPEC_VERSION}); @@ -922,6 +929,8 @@ VkResult EnumerateInstanceExtensionProperties( loader_extensions.push_back({ VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION}); + loader_extensions.push_back({VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME, + VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION}); static const VkExtensionProperties loader_debug_report_extension = { VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION, diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index 5f37a50a03..b436db1de7 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -565,11 +565,13 @@ ProcHook::Extension GetProcHookExtension(const char* name) { if (strcmp(name, "VK_EXT_hdr_metadata") == 0) return ProcHook::EXT_hdr_metadata; if (strcmp(name, "VK_EXT_swapchain_colorspace") == 0) return ProcHook::EXT_swapchain_colorspace; if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing; + if (strcmp(name, "VK_GOOGLE_surfaceless_query") == 0) return ProcHook::GOOGLE_surfaceless_query; if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface; if (strcmp(name, "VK_KHR_get_surface_capabilities2") == 0) return ProcHook::KHR_get_surface_capabilities2; if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present; if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image; if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface; + if (strcmp(name, "VK_KHR_surface_protected_capabilities") == 0) return ProcHook::KHR_surface_protected_capabilities; if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain; if (strcmp(name, "VK_ANDROID_external_memory_android_hardware_buffer") == 0) return ProcHook::ANDROID_external_memory_android_hardware_buffer; if (strcmp(name, "VK_KHR_bind_memory2") == 0) return ProcHook::KHR_bind_memory2; diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 047e774004..688630c0a5 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -41,11 +41,13 @@ struct ProcHook { EXT_hdr_metadata, EXT_swapchain_colorspace, GOOGLE_display_timing, + GOOGLE_surfaceless_query, KHR_android_surface, KHR_get_surface_capabilities2, KHR_incremental_present, KHR_shared_presentable_image, KHR_surface, + KHR_surface_protected_capabilities, KHR_swapchain, ANDROID_external_memory_android_hardware_buffer, KHR_bind_memory2, diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 6191063894..ec673123b0 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -614,42 +614,65 @@ VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/, VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( - VkPhysicalDevice /*pdev*/, + VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities) { ATRACE_CALL(); int err; - ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - int width, height; - err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - int transform_hint; - err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; - } - int max_buffer_count; - err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count); - if (err != android::OK) { - ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", - strerror(-err), err); - return VK_ERROR_SURFACE_LOST_KHR; + if (surface == VK_NULL_HANDLE) { + const InstanceData& instance_data = GetData(pdev); + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + // It is an error to pass a surface==VK_NULL_HANDLE unless the + // VK_GOOGLE_surfaceless_query extension is enabled + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this + // extension for this function is for + // VkSurfaceProtectedCapabilitiesKHR::supportsProtected. The following + // four values cannot be known without a surface. Default values will + // be supplied anyway, but cannot be relied upon. + width = 1000; + height = 1000; + transform_hint = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + max_buffer_count = 10; + } else { + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + + err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, + &transform_hint); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } + + err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, + &max_buffer_count); + if (err != android::OK) { + ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)", + strerror(-err), err); + return VK_ERROR_SURFACE_LOST_KHR; + } } capabilities->minImageCount = std::min(max_buffer_count, 3); capabilities->maxImageCount = static_cast<uint32_t>(max_buffer_count); @@ -690,23 +713,43 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, const InstanceData& instance_data = GetData(pdev); bool wide_color_support = false; - Surface& surface = *SurfaceFromHandle(surface_handle); - int err = native_window_get_wide_color_support(surface.window.get(), - &wide_color_support); - if (err) { - return VK_ERROR_SURFACE_LOST_KHR; - } - ALOGV("wide_color_support is: %d", wide_color_support); - wide_color_support = - wide_color_support && + uint64_t consumer_usage = 0; + bool swapchain_ext = instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace); + if (surface_handle == VK_NULL_HANDLE) { + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The EGL loader + // unconditionally supports wide color formats, even if they will cause + // a SurfaceFlinger fallback. Based on that, wide_color_support will be + // set to true in this case. + wide_color_support = true; + + // TODO(b/203826952): research proper value; temporarily use the + // values seen on Pixel + consumer_usage = AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY; + } else { + Surface& surface = *SurfaceFromHandle(surface_handle); + int err = native_window_get_wide_color_support(surface.window.get(), + &wide_color_support); + if (err) { + return VK_ERROR_SURFACE_LOST_KHR; + } + ALOGV("wide_color_support is: %d", wide_color_support); + + consumer_usage = surface.consumer_usage; + } + wide_color_support = wide_color_support && swapchain_ext; AHardwareBuffer_Desc desc = {}; desc.width = 1; desc.height = 1; desc.layers = 1; - desc.usage = surface.consumer_usage | - AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + desc.usage = consumer_usage | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; // We must support R8G8B8A8 @@ -721,6 +764,10 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT}); } + // NOTE: Any new formats that are added must be coordinated across different + // Android users. This includes the ANGLE team (a layered implementation of + // OpenGL-ES). + desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; if (AHardwareBuffer_isSupported(&desc)) { all_formats.emplace_back(VkSurfaceFormatKHR{ @@ -753,6 +800,10 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, } } + // NOTE: Any new formats that are added must be coordinated across different + // Android users. This includes the ANGLE team (a layered implementation of + // OpenGL-ES). + VkResult result = VK_SUCCESS; if (formats) { uint32_t transfer_count = all_formats.size(); @@ -797,6 +848,12 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( .supportedUsageFlags; } break; + case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { + VkSurfaceProtectedCapabilitiesKHR* protected_caps = + reinterpret_cast<VkSurfaceProtectedCapabilitiesKHR*>(caps); + protected_caps->supportsProtected = VK_TRUE; + } break; + default: // Ignore all other extension structs break; @@ -848,31 +905,51 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, int err; int query_value; - ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); + std::vector<VkPresentModeKHR> present_modes; + if (surface == VK_NULL_HANDLE) { + const InstanceData& instance_data = GetData(pdev); + ProcHook::Extension surfaceless = ProcHook::GOOGLE_surfaceless_query; + bool surfaceless_enabled = + instance_data.hook_extensions.test(surfaceless); + if (!surfaceless_enabled) { + return VK_ERROR_SURFACE_LOST_KHR; + } + // Support for VK_GOOGLE_surfaceless_query. The primary purpose of this + // extension for this function is for + // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR and + // VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR. We technically cannot + // know if VK_PRESENT_MODE_SHARED_MAILBOX_KHR is supported without a + // surface, and that cannot be relied upon. + present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); + present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); + } else { + ANativeWindow* window = SurfaceFromHandle(surface)->window.get(); - err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - &query_value); - if (err != android::OK || query_value < 0) { - ALOGE( - "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) " - "value=%d", - strerror(-err), err, query_value); - return VK_ERROR_SURFACE_LOST_KHR; - } - uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value); + err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &query_value); + if (err != android::OK || query_value < 0) { + ALOGE( + "NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) " + "value=%d", + strerror(-err), err, query_value); + return VK_ERROR_SURFACE_LOST_KHR; + } + uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value); + + err = + window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value); + if (err != android::OK || query_value < 0) { + ALOGE( + "NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d", + strerror(-err), err, query_value); + return VK_ERROR_SURFACE_LOST_KHR; + } + uint32_t max_buffer_count = static_cast<uint32_t>(query_value); - err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value); - if (err != android::OK || query_value < 0) { - ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d", - strerror(-err), err, query_value); - return VK_ERROR_SURFACE_LOST_KHR; + if (min_undequeued_buffers + 1 < max_buffer_count) + present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); + present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); } - uint32_t max_buffer_count = static_cast<uint32_t>(query_value); - - std::vector<VkPresentModeKHR> present_modes; - if (min_undequeued_buffers + 1 < max_buffer_count) - present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); - present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); VkPhysicalDevicePresentationPropertiesANDROID present_properties; QueryPresentationProperties(pdev, &present_properties); diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py index 6a73023193..af56764a21 100644 --- a/vulkan/scripts/driver_generator.py +++ b/vulkan/scripts/driver_generator.py @@ -27,11 +27,13 @@ _INTERCEPTED_EXTENSIONS = [ 'VK_EXT_hdr_metadata', 'VK_EXT_swapchain_colorspace', 'VK_GOOGLE_display_timing', + 'VK_GOOGLE_surfaceless_query', 'VK_KHR_android_surface', 'VK_KHR_get_surface_capabilities2', 'VK_KHR_incremental_present', 'VK_KHR_shared_presentable_image', 'VK_KHR_surface', + 'VK_KHR_surface_protected_capabilities', 'VK_KHR_swapchain', ] |