diff options
87 files changed, 1965 insertions, 560 deletions
diff --git a/.gitignore b/.gitignore index ed653c6b4a..1ad8a24a4b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ .idea/ .vscode/ *.code-workspace + +# Rust artifacts +**/target/ diff --git a/TEST_MAPPING b/TEST_MAPPING index cd8f3cdcc2..9c0116957d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -7,7 +7,8 @@ "include-filter": "*" }, { - "exclude-filter": "*ChildLayerTest#ChildrenSurviveParentDestruction" + // TODO(b/305717998): Deflake and re-enable + "exclude-filter": "*ChildLayerTest*" } ] }, diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index d73a30bf9b..e00c2a2b5a 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -24,7 +24,6 @@ cc_defaults { shared_libs: [ "libbase", - "libbinder", // also contains servicemanager_interface "libvintf", "libcutils", "liblog", @@ -33,6 +32,21 @@ cc_defaults { ], target: { + android: { + shared_libs: [ + "libbinder", + "libutils", + ], + }, + host: { + static_libs: [ + "libbinder", + "libutils", + ], + }, + darwin: { + enabled: false, + }, vendor: { exclude_shared_libs: ["libvintf"], }, diff --git a/data/etc/Android.bp b/data/etc/Android.bp index e95432c98f..1418e1f7a6 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -359,6 +359,12 @@ prebuilt_etc { } prebuilt_etc { + name: "android.software.opengles.deqp.level-latest.prebuilt.xml", + src: "android.software.opengles.deqp.level-latest.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { name: "android.software.sip.voip.prebuilt.xml", src: "android.software.sip.voip.xml", defaults: ["frameworks_native_data_etc_defaults"], @@ -389,6 +395,12 @@ prebuilt_etc { } prebuilt_etc { + name: "android.software.vulkan.deqp.level-latest.prebuilt.xml", + src: "android.software.vulkan.deqp.level-latest.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { name: "aosp_excluded_hardware.prebuilt.xml", src: "aosp_excluded_hardware.xml", defaults: ["frameworks_native_data_etc_defaults"], diff --git a/data/etc/android.software.opengles.deqp.level-latest.xml b/data/etc/android.software.opengles.deqp.level-latest.xml new file mode 100644 index 0000000000..bd15eb6eb2 --- /dev/null +++ b/data/etc/android.software.opengles.deqp.level-latest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2023 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. +--> + +<!-- This is the standard feature indicating that the device passes OpenGL ES + dEQP tests associated with the most recent level for this Android version. --> +<permissions> + <feature name="android.software.opengles.deqp.level" version="132580097" /> +</permissions> diff --git a/data/etc/android.software.vulkan.deqp.level-latest.xml b/data/etc/android.software.vulkan.deqp.level-latest.xml new file mode 100644 index 0000000000..87be0709d6 --- /dev/null +++ b/data/etc/android.software.vulkan.deqp.level-latest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2023 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. +--> + +<!-- This is the standard feature indicating that the device passes Vulkan + dEQP tests associated with the most recent level for this Android version. --> +<permissions> + <feature name="android.software.vulkan.deqp.level" version="132580097" /> +</permissions> diff --git a/data/etc/aosp_excluded_hardware.xml b/data/etc/aosp_excluded_hardware.xml index c12f4358c5..013f278f34 100644 --- a/data/etc/aosp_excluded_hardware.xml +++ b/data/etc/aosp_excluded_hardware.xml @@ -18,5 +18,4 @@ <!-- This should be used to exclude this feature from aosp targets. As aosp configurations may or may not have a valid location provider --> <unavailable-feature name="android.hardware.location.network" /> - <unavailable-feature name="android.software.device_id_attestation" /> </permissions> diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h index 645fa8a5e7..1d513a6abe 100644 --- a/include/android/sharedmem.h +++ b/include/android/sharedmem.h @@ -53,27 +53,27 @@ extern "C" { /** * Create a shared memory region. * - * Create shared memory region and returns a file descriptor. The resulting file descriptor can be - * mmap'ed to process memory space with PROT_READ | PROT_WRITE | PROT_EXEC. Access to shared memory - * region can be restricted with {@link ASharedMemory_setProt}. + * Create a shared memory region and returns a file descriptor. The resulting file descriptor can be + * mapped into the process' memory using mmap(2) with `PROT_READ | PROT_WRITE | PROT_EXEC`. + * Access to shared memory regions can be restricted with {@link ASharedMemory_setProt}. * - * Use close() to release the shared memory region. + * Use close(2) to release the shared memory region. * * Use <a href="/reference/android/os/ParcelFileDescriptor">android.os.ParcelFileDescriptor</a> * to pass the file descriptor to another process. File descriptors may also be sent to other - * processes over a Unix domain socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and + * processes over a Unix domain socket with sendmsg(2) and `SCM_RIGHTS`. See sendmsg(3) and * cmsg(3) man pages for more information. * * If you intend to share this file descriptor with a child process after - * calling exec(3), note that you will need to use fcntl(2) with F_SETFD - * to clear the FD_CLOEXEC flag for this to work on all versions of Android. + * calling exec(3), note that you will need to use fcntl(2) with `F_SETFD` + * to clear the `FD_CLOEXEC` flag for this to work on all versions of Android. * * Available since API level 26. * * \param name an optional name. * \param size size of the shared memory region * \return file descriptor that denotes the shared memory; - * -1 and sets errno on failure, or -EINVAL if the error is that size was 0. + * -1 and sets `errno` on failure, or `-EINVAL` if the error is that size was 0. */ int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26); @@ -83,7 +83,7 @@ int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26); * Available since API level 26. * * \param fd file descriptor of the shared memory region - * \return size in bytes; 0 if fd is not a valid shared memory file descriptor. + * \return size in bytes; 0 if `fd` is not a valid shared memory file descriptor. */ size_t ASharedMemory_getSize(int fd) __INTRODUCED_IN(26); @@ -115,9 +115,9 @@ size_t ASharedMemory_getSize(int fd) __INTRODUCED_IN(26); * Available since API level 26. * * \param fd file descriptor of the shared memory region. - * \param prot any bitwise-or'ed combination of PROT_READ, PROT_WRITE, PROT_EXEC denoting + * \param prot any bitwise-or'ed combination of `PROT_READ`, `PROT_WRITE`, `PROT_EXEC` denoting * updated access. Note access can only be removed, but not added back. - * \return 0 for success, -1 and sets errno on failure. + * \return 0 for success, -1 and sets `errno` on failure. */ int ASharedMemory_setProt(int fd, int prot) __INTRODUCED_IN(26); diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 6c2b313f8a..620c23c1bb 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -118,7 +118,8 @@ cc_defaults { ], srcs: [ - "OS.cpp", + "OS_android.cpp", + "OS_unix_base.cpp", "RpcTransportRaw.cpp", ], @@ -249,6 +250,7 @@ cc_library_shared { srcs: [ // Trusty-specific files + "OS_android.cpp", "trusty/logging.cpp", "trusty/OS.cpp", "trusty/RpcServerTrusty.cpp", @@ -357,6 +359,38 @@ cc_library_static { } cc_library_static { + name: "libbinder_rpc_no_blob", + vendor_available: true, + defaults: [ + "libbinder_common_defaults", + "libbinder_android_defaults", + "libbinder_kernel_defaults", + ], + cflags: [ + "-DBINDER_DISABLE_BLOB", + ], + visibility: [ + ":__subpackages__", + ], +} + +cc_library_static { + name: "libbinder_rpc_no_native_handle", + vendor_available: true, + defaults: [ + "libbinder_common_defaults", + "libbinder_android_defaults", + "libbinder_kernel_defaults", + ], + cflags: [ + "-DBINDER_DISABLE_NATIVE_HANDLE", + ], + visibility: [ + ":__subpackages__", + ], +} + +cc_library_static { name: "libbinder_rpc_single_threaded", defaults: [ "libbinder_common_defaults", diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 0f4a6cabde..f22e90a03f 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -29,8 +29,6 @@ #include <binder/Parcel.h> #include <binder/RecordedTransaction.h> #include <binder/RpcServer.h> -#include <cutils/compiler.h> -#include <private/android_filesystem_config.h> #include <pthread.h> #include <utils/misc.h> @@ -42,10 +40,13 @@ #endif #include "BuildFlags.h" +#include "OS.h" #include "RpcState.h" namespace android { +constexpr uid_t kUidRoot = 0; + // Service implementations inherit from BBinder and IBinder, and this is frozen // in prebuilts. #ifdef __LP64__ @@ -301,7 +302,7 @@ status_t BBinder::startRecordingTransactions(const Parcel& data) { return INVALID_OPERATION; } uid_t uid = IPCThreadState::self()->getCallingUid(); - if (uid != AID_ROOT) { + if (uid != kUidRoot) { ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid); return PERMISSION_DENIED; } @@ -331,7 +332,7 @@ status_t BBinder::stopRecordingTransactions() { return INVALID_OPERATION; } uid_t uid = IPCThreadState::self()->getCallingUid(); - if (uid != AID_ROOT) { + if (uid != kUidRoot) { ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid); return PERMISSION_DENIED; } @@ -402,7 +403,7 @@ status_t BBinder::transact( } } - if (CC_UNLIKELY(kEnableKernelIpc && mRecordingOn && code != START_RECORDING_TRANSACTION)) { + if (kEnableKernelIpc && mRecordingOn && code != START_RECORDING_TRANSACTION) [[unlikely]] { Extras* e = mExtras.load(std::memory_order_acquire); AutoMutex lock(e->mLock); if (mRecordingOn) { @@ -635,7 +636,7 @@ status_t BBinder::setRpcClientDebug(const Parcel& data) { return INVALID_OPERATION; } uid_t uid = IPCThreadState::self()->getCallingUid(); - if (uid != AID_ROOT) { + if (uid != kUidRoot) { ALOGE("%s: not allowed because client %" PRIu32 " is not root", __PRETTY_FUNCTION__, uid); return PERMISSION_DENIED; } @@ -795,7 +796,7 @@ status_t BBinder::onTransact( } case SYSPROPS_TRANSACTION: { - report_sysprop_change(); + if (!binder::os::report_sysprop_change()) return INVALID_OPERATION; return NO_ERROR; } diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 589df9aceb..3bc4f929e7 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -23,7 +23,6 @@ #include <binder/IResultReceiver.h> #include <binder/RpcSession.h> #include <binder/Stability.h> -#include <cutils/compiler.h> #include <utils/Log.h> #include <stdio.h> @@ -54,6 +53,11 @@ uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; // Another arbitrary value a binder count needs to drop below before another callback will be called uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000; +std::atomic<uint32_t> BpBinder::sBinderProxyCount(0); +std::atomic<uint32_t> BpBinder::sBinderProxyCountWarned(0); + +static constexpr uint32_t kBinderProxyCountWarnInterval = 5000; + // Log any transactions for which the data exceeds this size #define LOG_TRANSACTIONS_OVER_SIZE (300 * 1024) @@ -161,7 +165,7 @@ sp<BpBinder> BpBinder::create(int32_t handle) { trackedUid = IPCThreadState::self()->getCallingUid(); AutoMutex _l(sTrackingLock); uint32_t trackedValue = sTrackingMap[trackedUid]; - if (CC_UNLIKELY(trackedValue & LIMIT_REACHED_MASK)) { + if (trackedValue & LIMIT_REACHED_MASK) [[unlikely]] { if (sBinderProxyThrottleCreate) { return nullptr; } @@ -193,6 +197,18 @@ sp<BpBinder> BpBinder::create(int32_t handle) { } sTrackingMap[trackedUid]++; } + uint32_t numProxies = sBinderProxyCount.fetch_add(1, std::memory_order_relaxed); + uint32_t numLastWarned = sBinderProxyCountWarned.load(std::memory_order_relaxed); + uint32_t numNextWarn = numLastWarned + kBinderProxyCountWarnInterval; + if (numProxies >= numNextWarn) { + // Multiple threads can get here, make sure only one of them gets to + // update the warn counter. + if (sBinderProxyCountWarned.compare_exchange_strong(numLastWarned, + numNextWarn, + std::memory_order_relaxed)) { + ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies); + } + } return sp<BpBinder>::make(BinderHandle{handle}, trackedUid); } @@ -347,7 +363,7 @@ status_t BpBinder::transact( Stability::Level required = privateVendor ? Stability::VENDOR : Stability::getLocalLevel(); - if (CC_UNLIKELY(!Stability::check(stability, required))) { + if (!Stability::check(stability, required)) [[unlikely]] { ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.", Stability::levelString(stability).c_str(), String8(getInterfaceDescriptor()).c_str(), @@ -357,7 +373,7 @@ status_t BpBinder::transact( } status_t status; - if (CC_UNLIKELY(isRpcBinder())) { + if (isRpcBinder()) [[unlikely]] { status = rpcSession()->transact(sp<IBinder>::fromExisting(this), code, data, reply, flags); } else { @@ -572,7 +588,9 @@ BpBinder* BpBinder::remoteBinder() } BpBinder::~BpBinder() { - if (CC_UNLIKELY(isRpcBinder())) return; + if (isRpcBinder()) [[unlikely]] { + return; + } if constexpr (!kEnableKernelIpc) { LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time"); @@ -586,14 +604,13 @@ BpBinder::~BpBinder() { if (mTrackedUid >= 0) { AutoMutex _l(sTrackingLock); uint32_t trackedValue = sTrackingMap[mTrackedUid]; - if (CC_UNLIKELY((trackedValue & COUNTING_VALUE_MASK) == 0)) { + if ((trackedValue & COUNTING_VALUE_MASK) == 0) [[unlikely]] { ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, binderHandle()); } else { - if (CC_UNLIKELY( - (trackedValue & LIMIT_REACHED_MASK) && - ((trackedValue & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark) - )) { + auto countingValue = trackedValue & COUNTING_VALUE_MASK; + if ((trackedValue & LIMIT_REACHED_MASK) && + (countingValue <= sBinderProxyCountLowWatermark)) [[unlikely]] { ALOGI("Limit reached bit reset for uid %d (fewer than %d proxies from uid %d held)", getuid(), sBinderProxyCountLowWatermark, mTrackedUid); sTrackingMap[mTrackedUid] &= ~LIMIT_REACHED_MASK; @@ -604,6 +621,7 @@ BpBinder::~BpBinder() { } } } + --sBinderProxyCount; if (ipc) { ipc->expungeHandle(binderHandle(), this); @@ -612,7 +630,9 @@ BpBinder::~BpBinder() { } void BpBinder::onFirstRef() { - if (CC_UNLIKELY(isRpcBinder())) return; + if (isRpcBinder()) [[unlikely]] { + return; + } if constexpr (!kEnableKernelIpc) { LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time"); @@ -625,7 +645,7 @@ void BpBinder::onFirstRef() { } void BpBinder::onLastStrongRef(const void* /*id*/) { - if (CC_UNLIKELY(isRpcBinder())) { + if (isRpcBinder()) [[unlikely]] { (void)rpcSession()->sendDecStrong(this); return; } @@ -666,7 +686,9 @@ void BpBinder::onLastStrongRef(const void* /*id*/) { bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) { // RPC binder doesn't currently support inc from weak binders - if (CC_UNLIKELY(isRpcBinder())) return false; + if (isRpcBinder()) [[unlikely]] { + return false; + } if constexpr (!kEnableKernelIpc) { LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time"); @@ -688,6 +710,11 @@ uint32_t BpBinder::getBinderProxyCount(uint32_t uid) return 0; } +uint32_t BpBinder::getBinderProxyCount() +{ + return sBinderProxyCount.load(); +} + void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts) { AutoMutex _l(sTrackingLock); diff --git a/libs/binder/OS.h b/libs/binder/OS.h index fecae31763..8dc1f6ae70 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -23,7 +23,7 @@ #include <binder/RpcTransport.h> #include <utils/Errors.h> -namespace android { +namespace android::binder::os { android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd); @@ -41,4 +41,8 @@ ssize_t receiveMessageFromSocket( const RpcTransportFd& socket, iovec* iovs, int niovs, std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds); -} // namespace android +uint64_t GetThreadId(); + +bool report_sysprop_change(); + +} // namespace android::binder::os diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp new file mode 100644 index 0000000000..ad458eb705 --- /dev/null +++ b/libs/binder/OS_android.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2023 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 "OS.h" + +#include <android-base/threads.h> +#include <utils/misc.h> + +namespace android::binder::os { + +uint64_t GetThreadId() { +#ifdef BINDER_RPC_SINGLE_THREADED + return 0; +#else + return base::GetThreadId(); +#endif +} + +bool report_sysprop_change() { + android::report_sysprop_change(); + return true; +} + +} // namespace android::binder::os diff --git a/libs/binder/OS.cpp b/libs/binder/OS_unix_base.cpp index ce60e33ba7..81933d5c6b 100644 --- a/libs/binder/OS.cpp +++ b/libs/binder/OS_unix_base.cpp @@ -24,7 +24,7 @@ using android::base::ErrnoError; using android::base::Result; -namespace android { +namespace android::binder::os { // Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets. constexpr size_t kMaxFdsPerMsg = 253; @@ -162,4 +162,4 @@ ssize_t receiveMessageFromSocket( return TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); } -} // namespace android +} // namespace android::binder::os diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 5b34efc257..17bdc455be 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -40,8 +40,9 @@ #include <binder/TextOutput.h> #include <android-base/scopeguard.h> +#ifndef BINDER_DISABLE_BLOB #include <cutils/ashmem.h> -#include <cutils/compiler.h> +#endif #include <utils/Flattenable.h> #include <utils/Log.h> #include <utils/String16.h> @@ -622,7 +623,7 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { // To match kernel binder behavior, we always dup, even if the // FD was unowned in the source parcel. int newFd = -1; - if (status_t status = dupFileDescriptor(oldFd, &newFd); status != OK) { + if (status_t status = binder::os::dupFileDescriptor(oldFd, &newFd); status != OK) { ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status)); } rpcFields->mFds->emplace_back(base::unique_fd(newFd)); @@ -1435,6 +1436,7 @@ status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) { return writeParcelable(*parcelable); } +#ifndef BINDER_DISABLE_NATIVE_HANDLE status_t Parcel::writeNativeHandle(const native_handle* handle) { if (!handle || handle->version != sizeof(native_handle)) @@ -1457,6 +1459,7 @@ status_t Parcel::writeNativeHandle(const native_handle* handle) err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts); return err; } +#endif status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { if (auto* rpcFields = maybeRpcFields()) { @@ -1514,7 +1517,7 @@ status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { status_t Parcel::writeDupFileDescriptor(int fd) { int dupFd; - if (status_t err = dupFileDescriptor(fd, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(fd, &dupFd); err != OK) { return err; } status_t err = writeFileDescriptor(dupFd, true /*takeOwnership*/); @@ -1533,7 +1536,7 @@ status_t Parcel::writeParcelFileDescriptor(int fd, bool takeOwnership) status_t Parcel::writeDupParcelFileDescriptor(int fd) { int dupFd; - if (status_t err = dupFileDescriptor(fd, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(fd, &dupFd); err != OK) { return err; } status_t err = writeParcelFileDescriptor(dupFd, true /*takeOwnership*/); @@ -1549,6 +1552,12 @@ status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) { status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) { +#ifdef BINDER_DISABLE_BLOB + (void)len; + (void)mutableCopy; + (void)outBlob; + return INVALID_OPERATION; +#else if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. @@ -1600,6 +1609,7 @@ status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) } ::close(fd); return status; +#endif } status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd) @@ -2231,6 +2241,7 @@ int32_t Parcel::readExceptionCode() const return status.exceptionCode(); } +#ifndef BINDER_DISABLE_NATIVE_HANDLE native_handle* Parcel::readNativeHandle() const { int numFds, numInts; @@ -2263,6 +2274,7 @@ native_handle* Parcel::readNativeHandle() const } return h; } +#endif int Parcel::readFileDescriptor() const { if (const auto* rpcFields = maybeRpcFields()) { @@ -2346,7 +2358,7 @@ status_t Parcel::readUniqueFileDescriptor(base::unique_fd* val) const } int dupFd; - if (status_t err = dupFileDescriptor(got, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(got, &dupFd); err != OK) { return BAD_VALUE; } @@ -2368,7 +2380,7 @@ status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const } int dupFd; - if (status_t err = dupFileDescriptor(got, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(got, &dupFd); err != OK) { return BAD_VALUE; } @@ -2383,6 +2395,11 @@ status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const { +#ifdef BINDER_DISABLE_BLOB + (void)len; + (void)outBlob; + return INVALID_OPERATION; +#else int32_t blobType; status_t status = readInt32(&blobType); if (status) return status; @@ -2416,6 +2433,7 @@ status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const outBlob->init(fd, ptr, len, isMutable); return NO_ERROR; +#endif } status_t Parcel::read(FlattenableHelperInterface& val) const @@ -3159,6 +3177,7 @@ size_t Parcel::getOpenAshmemSize() const } size_t openAshmemSize = 0; +#ifndef BINDER_DISABLE_BLOB for (size_t i = 0; i < kernelFields->mObjectsSize; i++) { const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + kernelFields->mObjects[i]); @@ -3173,6 +3192,7 @@ size_t Parcel::getOpenAshmemSize() const } } } +#endif return openAshmemSize; } #endif // BINDER_WITH_KERNEL_IPC diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 55fc16de45..07ab093992 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "RpcServer" #include <inttypes.h> +#include <netinet/tcp.h> #include <poll.h> #include <sys/socket.h> #include <sys/un.h> @@ -24,7 +25,6 @@ #include <thread> #include <vector> -#include <android-base/hex.h> #include <android-base/scopeguard.h> #include <binder/Parcel.h> #include <binder/RpcServer.h> @@ -57,7 +57,7 @@ RpcServer::~RpcServer() { sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) { // Default is without TLS. if (rpcTransportCtxFactory == nullptr) - rpcTransportCtxFactory = makeDefaultRpcTransportCtxFactory(); + rpcTransportCtxFactory = binder::os::makeDefaultRpcTransportCtxFactory(); auto ctx = rpcTransportCtxFactory->newServerCtx(); if (ctx == nullptr) return nullptr; return sp<RpcServer>::make(std::move(ctx)); @@ -216,7 +216,7 @@ status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTranspor iovec iov{&zero, sizeof(zero)}; std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; - ssize_t num_bytes = receiveMessageFromSocket(server.mServer, &iov, 1, &fds); + ssize_t num_bytes = binder::os::receiveMessageFromSocket(server.mServer, &iov, 1, &fds); if (num_bytes < 0) { int savedErrno = errno; ALOGE("Failed recvmsg: %s", strerror(savedErrno)); @@ -231,7 +231,7 @@ status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTranspor } unique_fd fd(std::move(std::get<unique_fd>(fds.back()))); - if (auto res = setNonBlocking(fd); !res.ok()) { + if (auto res = binder::os::setNonBlocking(fd); !res.ok()) { ALOGE("Failed setNonBlocking: %s", res.error().message().c_str()); return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code(); } @@ -484,11 +484,11 @@ void RpcServer::establishConnection( // don't block if there is some entropy issue if (tries++ > 5) { ALOGE("Cannot find new address: %s", - base::HexString(sessionId.data(), sessionId.size()).c_str()); + HexString(sessionId.data(), sessionId.size()).c_str()); return; } - auto status = getRandomBytes(sessionId.data(), sessionId.size()); + auto status = binder::os::getRandomBytes(sessionId.data(), sessionId.size()); if (status != OK) { ALOGE("Failed to read random session ID: %s", strerror(-status)); return; @@ -536,7 +536,7 @@ void RpcServer::establishConnection( auto it = server->mSessions.find(sessionId); if (it == server->mSessions.end()) { ALOGE("Cannot add thread, no record of session with ID %s", - base::HexString(sessionId.data(), sessionId.size()).c_str()); + HexString(sessionId.data(), sessionId.size()).c_str()); return; } session = it->second; @@ -572,6 +572,17 @@ status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) { return -savedErrno; } + if (addr.addr()->sa_family == AF_INET || addr.addr()->sa_family == AF_INET6) { + int noDelay = 1; + int result = + setsockopt(socket_fd.get(), IPPROTO_TCP, TCP_NODELAY, &noDelay, sizeof(noDelay)); + if (result < 0) { + int savedErrno = errno; + ALOGE("Could not set TCP_NODELAY on %s", strerror(savedErrno)); + return -savedErrno; + } + } + { RpcMutexLockGuard _l(mLock); if (mServerSocketModifier != nullptr) { @@ -610,15 +621,14 @@ status_t RpcServer::setupRawSocketServer(unique_fd socket_fd) { void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) { const std::vector<uint8_t>& id = session->mId; LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID"); - LOG_RPC_DETAIL("Dropping session with address %s", - base::HexString(id.data(), id.size()).c_str()); + LOG_RPC_DETAIL("Dropping session with address %s", HexString(id.data(), id.size()).c_str()); RpcMutexLockGuard _l(mLock); auto it = mSessions.find(id); LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s", - base::HexString(id.data(), id.size()).c_str()); + HexString(id.data(), id.size()).c_str()); LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %s", - base::HexString(id.data(), id.size()).c_str()); + HexString(id.data(), id.size()).c_str()); (void)mSessions.erase(it); } diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index c3dee1650e..fa8f2b51ac 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -26,7 +26,6 @@ #include <string_view> -#include <android-base/hex.h> #include <android-base/macros.h> #include <android-base/scopeguard.h> #include <binder/BpBinder.h> @@ -70,7 +69,7 @@ RpcSession::~RpcSession() { sp<RpcSession> RpcSession::make() { // Default is without TLS. - return make(makeDefaultRpcTransportCtxFactory()); + return make(binder::os::makeDefaultRpcTransportCtxFactory()); } sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) { @@ -195,7 +194,7 @@ status_t RpcSession::setupPreconnectedClient(base::unique_fd fd, fd = request(); if (!fd.ok()) return BAD_VALUE; } - if (auto res = setNonBlocking(fd); !res.ok()) { + if (auto res = binder::os::setNonBlocking(fd); !res.ok()) { ALOGE("setupPreconnectedClient: %s", res.error().message().c_str()); return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code(); } @@ -310,8 +309,7 @@ status_t RpcSession::readId() { status = state()->getSessionId(connection.get(), sp<RpcSession>::fromExisting(this), &mId); if (status != OK) return status; - LOG_RPC_DETAIL("RpcSession %p has id %s", this, - base::HexString(mId.data(), mId.size()).c_str()); + LOG_RPC_DETAIL("RpcSession %p has id %s", this, HexString(mId.data(), mId.size()).c_str()); return OK; } @@ -709,7 +707,7 @@ status_t RpcSession::initAndAddConnection(RpcTransportFd fd, const std::vector<u std::nullopt, nullptr); if (sendSessionIdStatus != OK) { ALOGE("Could not write session ID ('%s') to socket: %s", - base::HexString(sessionId.data(), sessionId.size()).c_str(), + HexString(sessionId.data(), sessionId.size()).c_str(), statusToString(sendSessionIdStatus).c_str()); return sendSessionIdStatus; } @@ -770,7 +768,7 @@ status_t RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTran { RpcMutexLockGuard _l(mMutex); connection->rpcTransport = std::move(rpcTransport); - connection->exclusiveTid = rpcGetThreadId(); + connection->exclusiveTid = binder::os::GetThreadId(); mConnections.mOutgoing.push_back(connection); } @@ -825,7 +823,7 @@ sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread( sp<RpcConnection> session = sp<RpcConnection>::make(); session->rpcTransport = std::move(rpcTransport); - session->exclusiveTid = rpcGetThreadId(); + session->exclusiveTid = binder::os::GetThreadId(); mConnections.mIncoming.push_back(session); mConnections.mMaxIncoming = mConnections.mIncoming.size(); @@ -870,7 +868,7 @@ status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, Co connection->mConnection = nullptr; connection->mReentrant = false; - uint64_t tid = rpcGetThreadId(); + uint64_t tid = binder::os::GetThreadId(); RpcMutexUniqueLock _l(session->mMutex); session->mConnections.mWaitingThreads++; diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index bac2808b26..5046253837 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -18,7 +18,6 @@ #include "RpcState.h" -#include <android-base/hex.h> #include <android-base/macros.h> #include <android-base/scopeguard.h> #include <android-base/stringprintf.h> @@ -363,7 +362,7 @@ status_t RpcState::rpcSend( for (int i = 0; i < niovs; i++) { LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s", what, i + 1, niovs, connection->rpcTransport.get(), - android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); + HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); } if (status_t status = @@ -398,7 +397,7 @@ status_t RpcState::rpcRec( for (int i = 0; i < niovs; i++) { LOG_RPC_DETAIL("Received %s (part %d of %d) on RpcTransport %p: %s", what, i + 1, niovs, connection->rpcTransport.get(), - android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); + HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); } return OK; } @@ -409,10 +408,11 @@ bool RpcState::validateProtocolVersion(uint32_t version) { char codename[PROPERTY_VALUE_MAX]; property_get("ro.build.version.codename", codename, ""); if (!strcmp(codename, "REL")) { - ALOGE("Cannot use experimental RPC binder protocol on a release branch."); + ALOGE("Cannot use experimental RPC binder protocol in a release configuration."); return false; } #else + // TODO(b/305983144) // don't restrict on other platforms, though experimental should // only really be used for testing, we don't have a good way to see // what is shipping outside of Android diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index ddbcb573b1..c089811561 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -59,8 +59,8 @@ public: override { bool sentFds = false; auto send = [&](iovec* iovs, int niovs) -> ssize_t { - ssize_t ret = - sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds); + ssize_t ret = binder::os::sendMessageOnSocket(mSocket, iovs, niovs, + sentFds ? nullptr : ancillaryFds); sentFds |= ret > 0; return ret; }; @@ -73,7 +73,7 @@ public: const std::optional<android::base::function_ref<status_t()>>& altPoll, std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { auto recv = [&](iovec* iovs, int niovs) -> ssize_t { - return receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds); + return binder::os::receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds); }; return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll); diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp index 0314b0fea7..47fd17dcb1 100644 --- a/libs/binder/Utils.cpp +++ b/libs/binder/Utils.cpp @@ -16,6 +16,7 @@ #include "Utils.h" +#include <android-base/logging.h> #include <string.h> namespace android { @@ -24,4 +25,22 @@ void zeroMemory(uint8_t* data, size_t size) { memset(data, 0, size); } +std::string HexString(const void* bytes, size_t len) { + CHECK(bytes != nullptr || len == 0) << bytes << " " << len; + + // b/132916539: Doing this the 'C way', std::setfill triggers ubsan implicit conversion + const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes); + const char chars[] = "0123456789abcdef"; + std::string result; + result.resize(len * 2); + + for (size_t i = 0; i < len; i++) { + const auto c = bytes8[i]; + result[2 * i] = chars[c >> 4]; + result[2 * i + 1] = chars[c & 0xf]; + } + + return result; +} + } // namespace android diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h index e04199c75a..dd632c0b26 100644 --- a/libs/binder/Utils.h +++ b/libs/binder/Utils.h @@ -70,4 +70,10 @@ struct Span { } }; +// Converts binary data into a hexString. +// +// Hex values are printed in order, e.g. 0xDEAD will result in 'adde' because +// Android is little-endian. +std::string HexString(const void* bytes, size_t len); + } // namespace android diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index fc8089d069..28fb9f1bbc 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -88,6 +88,7 @@ public: static void setCountByUidEnabled(bool enable); static void setLimitCallback(binder_proxy_limit_callback cb); static void setBinderProxyCountWatermarks(int high, int low); + static uint32_t getBinderProxyCount(); std::optional<int32_t> getDebugBinderHandle() const; @@ -209,6 +210,8 @@ private: static uint32_t sBinderProxyCountLowWatermark; static bool sBinderProxyThrottleCreate; static std::unordered_map<int32_t,uint32_t> sLastLimitCallbackMap; + static std::atomic<uint32_t> sBinderProxyCount; + static std::atomic<uint32_t> sBinderProxyCountWarned; }; } // namespace android diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 45e5ace73c..98d12bb120 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -26,7 +26,9 @@ #include <vector> #include <android-base/unique_fd.h> +#ifndef BINDER_DISABLE_NATIVE_HANDLE #include <cutils/native_handle.h> +#endif #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/String16.h> @@ -324,11 +326,13 @@ public: template<typename T> status_t writeVectorSize(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead"))); +#ifndef BINDER_DISABLE_NATIVE_HANDLE // Place a native_handle into the parcel (the native_handle's file- // descriptors are dup'ed, so it is safe to delete the native_handle // when this function returns). // Doesn't take ownership of the native_handle. status_t writeNativeHandle(const native_handle* handle); +#endif // Place a file descriptor into the parcel. The given fd must remain // valid for the lifetime of the parcel. @@ -559,13 +563,14 @@ public: // response headers rather than doing it by hand. int32_t readExceptionCode() const; +#ifndef BINDER_DISABLE_NATIVE_HANDLE // Retrieve native_handle from the parcel. This returns a copy of the // parcel's native_handle (the caller takes ownership). The caller - // must free the native_handle with native_handle_close() and + // must free the native_handle with native_handle_close() and // native_handle_delete(). native_handle* readNativeHandle() const; +#endif - // Retrieve a file descriptor from the parcel. This returns the raw fd // in the parcel, which you do not own -- use dup() to get your own copy. int readFileDescriptor() const; @@ -1289,6 +1294,7 @@ private: // Fields only needed when parcelling for "kernel Binder". struct KernelFields { + KernelFields() {} binder_size_t* mObjects = nullptr; size_t mObjectsSize = 0; size_t mObjectsCapacity = 0; diff --git a/libs/binder/include/binder/RpcThreads.h b/libs/binder/include/binder/RpcThreads.h index b80d116e1c..d25f29277c 100644 --- a/libs/binder/include/binder/RpcThreads.h +++ b/libs/binder/include/binder/RpcThreads.h @@ -17,8 +17,6 @@ #include <pthread.h> -#include <android-base/threads.h> - #include <condition_variable> #include <functional> #include <memory> @@ -121,10 +119,6 @@ static inline RpcMaybeThread::id get_id() { } } // namespace rpc_this_thread -static inline uint64_t rpcGetThreadId() { - return 0; -} - static inline void rpcJoinIfSingleThreaded(RpcMaybeThread& t) { t.join(); } @@ -136,10 +130,6 @@ using RpcConditionVariable = std::condition_variable; using RpcMaybeThread = std::thread; namespace rpc_this_thread = std::this_thread; -static inline uint64_t rpcGetThreadId() { - return base::GetThreadId(); -} - static inline void rpcJoinIfSingleThreaded(RpcMaybeThread&) {} #endif // BINDER_RPC_SINGLE_THREADED diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h index 5fa2ff6a87..96b9733c94 100644 --- a/libs/binder/include/binder/SafeInterface.h +++ b/libs/binder/include/binder/SafeInterface.h @@ -18,7 +18,6 @@ #include <binder/IInterface.h> #include <binder/Parcel.h> -#include <cutils/compiler.h> // Set to 1 to enable CallStacks when logging errors #define SI_DUMP_CALLSTACKS 0 @@ -218,7 +217,7 @@ private: template <typename Function> status_t callParcel(const char* name, Function f) const { status_t error = f(); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { ALOG(LOG_ERROR, mLogTag, "Failed to %s, (%d: %s)", name, error, strerror(-error)); #if SI_DUMP_CALLSTACKS CallStack callStack(mLogTag); @@ -265,7 +264,7 @@ protected: data.writeInterfaceToken(this->getInterfaceDescriptor()); status_t error = writeInputs(&data, std::forward<Args>(args)...); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by writeInputs return error; } @@ -273,7 +272,7 @@ protected: // Send the data Parcel to the remote and retrieve the reply parcel Parcel reply; error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error); #if SI_DUMP_CALLSTACKS CallStack callStack(mLogTag); @@ -283,7 +282,7 @@ protected: // Read the outputs from the reply Parcel into the output arguments error = readOutputs(reply, std::forward<Args>(args)...); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by readOutputs return error; } @@ -291,7 +290,7 @@ protected: // Retrieve the result code from the reply Parcel status_t result = NO_ERROR; error = reply.readInt32(&result); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { ALOG(LOG_ERROR, mLogTag, "Failed to obtain result"); #if SI_DUMP_CALLSTACKS CallStack callStack(mLogTag); @@ -315,7 +314,7 @@ protected: Parcel data; data.writeInterfaceToken(this->getInterfaceDescriptor()); status_t error = writeInputs(&data, std::forward<Args>(args)...); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by writeInputs return; } @@ -324,7 +323,7 @@ protected: Parcel reply; error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply, IBinder::FLAG_ONEWAY); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error); #if SI_DUMP_CALLSTACKS CallStack callStack(mLogTag); @@ -406,7 +405,7 @@ private: template <typename T, typename... Remaining> status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const { status_t error = writeIfInput(data, std::forward<T>(t)); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by writeIfInput return error; } @@ -429,7 +428,7 @@ private: template <typename T, typename... Remaining> status_t readOutputs(const Parcel& reply, T&& t, Remaining&&... remaining) const { status_t error = readIfOutput(reply, std::forward<T>(t)); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by readIfOutput return error; } @@ -458,7 +457,7 @@ protected: // Read the inputs from the data Parcel into the argument tuple status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by read return error; } @@ -468,14 +467,14 @@ protected: // Extract the outputs from the argument tuple and write them into the reply Parcel error = OutputWriter<ParamTuple>{mLogTag}.writeOutputs(reply, &rawArgs); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by write return error; } // Return the result code in the reply Parcel error = reply->writeInt32(result); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { ALOG(LOG_ERROR, mLogTag, "Failed to write result"); #if SI_DUMP_CALLSTACKS CallStack callStack(mLogTag); @@ -500,7 +499,7 @@ protected: // Read the inputs from the data Parcel into the argument tuple status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged by read return error; } @@ -596,7 +595,7 @@ private: typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg( const Parcel& data, RawTuple* args) { status_t error = readIfInput<I>(data, args); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged in read return error; } @@ -694,7 +693,7 @@ private: typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg( Parcel* reply, RawTuple* args) { status_t error = writeIfOutput<I>(reply, args); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged in read return error; } diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index f7dd9c9715..47da296b70 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -21,7 +21,9 @@ #include <android/binder_status.h> #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> +#if __has_include(<private/android_filesystem_config.h>) #include <private/android_filesystem_config.h> +#endif #include "ibinder_internal.h" #include "parcel_internal.h" @@ -229,7 +231,11 @@ status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parce // Shell commands should only be callable by ADB. uid_t uid = AIBinder_getCallingUid(); - if (uid != AID_ROOT && uid != AID_SHELL) { + if (uid != 0 /* root */ +#ifdef AID_SHELL + && uid != AID_SHELL +#endif + ) { if (resultReceiver != nullptr) { resultReceiver->send(-1); } diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 89fd7a38c1..316a79cfee 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -120,7 +120,7 @@ binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char /** * Gets a binder object with this specific instance name. Efficiently waits for the service. - * If the service is not declared, it will wait indefinitely. Requires the threadpool + * If the service is not ever registered, it will wait indefinitely. Requires the threadpool * to be started in the service. * This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible * for calling AIBinder_decStrong). diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp index 76acff50bf..3ee36cd8c3 100644 --- a/libs/binder/ndk/tests/iface.cpp +++ b/libs/binder/ndk/tests/iface.cpp @@ -156,7 +156,10 @@ binder_status_t IFoo::addService(const char* instance) { } sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr +#pragma clang diagnostic pop if (binder == nullptr) { return nullptr; } diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 15708ca738..cab1a60370 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -341,7 +341,10 @@ TEST(NdkBinder, UnimplementedShell) { // libbinder across processes to the NDK service which doesn't implement // shell static const sp<android::IServiceManager> sm(android::defaultServiceManager()); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> testService = sm->getService(String16(IFoo::kSomeInstanceName)); +#pragma clang diagnostic pop Vector<String16> argsVec; EXPECT_EQ(OK, IBinder::shellCommand(testService, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, @@ -384,7 +387,10 @@ TEST(NdkBinder, GetTestServiceStressTest) { // checkService on it, since the other process serving it might not be started yet. { // getService, not waitForService, to take advantage of timeout +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" auto binder = ndk::SpAIBinder(AServiceManager_getService(IFoo::kSomeInstanceName)); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder.get()); } @@ -574,7 +580,10 @@ TEST(NdkBinder, DeathRecipient) { } TEST(NdkBinder, RetrieveNonNdkService) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); EXPECT_TRUE(AIBinder_isRemote(binder)); EXPECT_TRUE(AIBinder_isAlive(binder)); @@ -588,7 +597,10 @@ void OnBinderDeath(void* cookie) { } TEST(NdkBinder, LinkToDeath) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(OnBinderDeath); @@ -618,7 +630,10 @@ TEST(NdkBinder, SetInheritRt) { } TEST(NdkBinder, SetInheritRtNonLocal) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop ASSERT_NE(binder, nullptr); ASSERT_TRUE(AIBinder_isRemote(binder)); @@ -654,11 +669,14 @@ TEST(NdkBinder, GetServiceInProcess) { } TEST(NdkBinder, EqualityOfRemoteBinderPointer) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binderA = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binderA); AIBinder* binderB = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binderB); +#pragma clang diagnostic pop EXPECT_EQ(binderA, binderB); @@ -672,7 +690,10 @@ TEST(NdkBinder, ToFromJavaNullptr) { } TEST(NdkBinder, ABpBinderRefCount) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop AIBinder_Weak* wBinder = AIBinder_Weak_new(binder); ASSERT_NE(nullptr, binder); @@ -695,7 +716,10 @@ TEST(NdkBinder, AddServiceMultipleTimes) { } TEST(NdkBinder, RequestedSidWorks) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); +#pragma clang diagnostic pop std::shared_ptr<aidl::IBinderNdkUnitTest> service = aidl::IBinderNdkUnitTest::fromBinder(binder); @@ -718,7 +742,10 @@ TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); +#pragma clang diagnostic pop std::shared_ptr<aidl::IBinderNdkUnitTest> service = aidl::IBinderNdkUnitTest::fromBinder(binder); @@ -741,7 +768,10 @@ TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { TEST(NdkBinder, ConvertToPlatformBinder) { for (const ndk::SpAIBinder& binder : {// remote +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)), +#pragma clang diagnostic pop // local ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) { // convert to platform binder @@ -774,7 +804,10 @@ TEST(NdkBinder, ConvertToPlatformParcel) { TEST(NdkBinder, GetAndVerifyScopedAIBinder_Weak) { for (const ndk::SpAIBinder& binder : {// remote +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)), +#pragma clang diagnostic pop // local ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) { // get a const ScopedAIBinder_Weak and verify promote @@ -869,7 +902,10 @@ std::string shellCmdToString(sp<IBinder> unitTestService, const std::vector<cons TEST(NdkBinder, UseHandleShellCommand) { static const sp<android::IServiceManager> sm(android::defaultServiceManager()); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> testService = sm->getService(String16(kBinderNdkUnitTestService)); +#pragma clang diagnostic pop EXPECT_EQ("", shellCmdToString(testService, {})); EXPECT_EQ("", shellCmdToString(testService, {"", ""})); @@ -879,7 +915,10 @@ TEST(NdkBinder, UseHandleShellCommand) { TEST(NdkBinder, FlaggedServiceAccessible) { static const sp<android::IServiceManager> sm(android::defaultServiceManager()); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> testService = sm->getService(String16(kBinderNdkUnitTestServiceFlagged)); +#pragma clang diagnostic pop ASSERT_NE(nullptr, testService); } diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 463c210316..a08cb7ab39 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -436,7 +436,7 @@ impl<I: FromIBinder + ?Sized> Ord for Strong<I> { impl<I: FromIBinder + ?Sized> PartialOrd for Strong<I> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - self.0.as_binder().partial_cmp(&other.0.as_binder()) + Some(self.cmp(other)) } } @@ -483,7 +483,7 @@ impl<I: FromIBinder + ?Sized> Ord for Weak<I> { impl<I: FromIBinder + ?Sized> PartialOrd for Weak<I> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - self.weak_binder.partial_cmp(&other.weak_binder) + Some(self.cmp(other)) } } diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 8841fe640b..ed870b6d8c 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -144,6 +144,7 @@ pub mod binder_impl { #[doc(hidden)] pub mod unstable_api { pub use crate::binder::AsNative; + pub use crate::error::status_result; pub use crate::proxy::unstable_api::new_spibinder; pub use crate::sys::AIBinder; pub use crate::sys::AParcel; diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 3c615edbc0..f9f135d572 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -54,6 +54,10 @@ pub struct Parcel { /// Safety: This type guarantees that it owns the AParcel and that all access to /// the AParcel happens through the Parcel, so it is ok to send across threads. +/// +/// It would not be okay to implement Sync, because that would allow you to call +/// the reading methods from several threads in parallel, which would be a data +/// race on the cursor position inside the AParcel. unsafe impl Send for Parcel {} /// Container for a message (data and object references) that can be sent diff --git a/libs/binder/rust/tests/serialization.hpp b/libs/binder/rust/tests/serialization.hpp index 0041608ae0..9edcd6d9b6 100644 --- a/libs/binder/rust/tests/serialization.hpp +++ b/libs/binder/rust/tests/serialization.hpp @@ -14,7 +14,10 @@ * limitations under the License. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpragma-once-outside-header" #pragma once +#pragma clang diagnostic pop #include <binder/IBinder.h> diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index 8e95d69ffc..5bf9680284 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -279,7 +279,10 @@ int main(int argc, char* argv[]) { while (-1 != (opt = getopt(argc, argv, "gi:"))) { switch (opt) { case 'g': { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" serviceRetriever = &android::IServiceManager::getService; +#pragma clang diagnostic pop } break; case 'i': { ip_address = optarg; diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp index 307151c7de..e43ee5fcf5 100644 --- a/libs/binder/tests/binderClearBufTest.cpp +++ b/libs/binder/tests/binderClearBufTest.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include <android-base/hex.h> #include <android-base/logging.h> #include <binder/Binder.h> #include <binder/IBinder.h> @@ -24,6 +23,8 @@ #include <binder/Stability.h> #include <gtest/gtest.h> +#include "../Utils.h" + #include <sys/prctl.h> #include <thread> @@ -68,13 +69,16 @@ class FooBar : public BBinder { lastReply = reply.data(); lastReplySize = reply.dataSize(); } - *outBuffer = android::base::HexString(lastReply, lastReplySize); + *outBuffer = android::HexString(lastReply, lastReplySize); return result; } }; TEST(BinderClearBuf, ClearKernelBuffer) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> binder = defaultServiceManager()->getService(kServerName); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); std::string replyBuffer; diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp index 77a5fa8d65..0075688ed3 100644 --- a/libs/binder/tests/binderHostDeviceTest.cpp +++ b/libs/binder/tests/binderHostDeviceTest.cpp @@ -135,7 +135,10 @@ TEST_F(HostDeviceTest, CheckService) { TEST_F(HostDeviceTest, GetService) { auto sm = defaultServiceManager(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" auto rpcBinder = sm->getService(String16(kServiceName)); +#pragma clang diagnostic pop ASSERT_NE(nullptr, rpcBinder); EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK)); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index e021af0264..341e9ce5ec 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -213,7 +213,10 @@ class BinderLibTestEnv : public ::testing::Environment { sp<IServiceManager> sm = defaultServiceManager(); //printf("%s: pid %d, get service\n", __func__, m_pid); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" m_server = sm->getService(binderLibTestServiceName); +#pragma clang diagnostic pop ASSERT_TRUE(m_server != nullptr); //printf("%s: pid %d, get service done\n", __func__, m_pid); } @@ -1107,6 +1110,7 @@ TEST_F(BinderLibTest, WorkSourcePropagatedForAllFollowingBinderCalls) status_t ret; data.writeInterfaceToken(binderLibTestServiceName); ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); Parcel data2, reply2; status_t ret2; @@ -1441,6 +1445,36 @@ TEST_F(BinderLibTest, HangingServices) { EXPECT_GE(epochMsAfter, epochMsBefore + delay); } +TEST_F(BinderLibTest, BinderProxyCount) { + Parcel data, reply; + sp<IBinder> server = addServer(); + ASSERT_NE(server, nullptr); + + uint32_t initialCount = BpBinder::getBinderProxyCount(); + size_t iterations = 100; + { + uint32_t count = initialCount; + std::vector<sp<IBinder> > proxies; + sp<IBinder> proxy; + // Create binder proxies and verify the count. + for (size_t i = 0; i < iterations; i++) { + ASSERT_THAT(server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply), + StatusEq(NO_ERROR)); + proxies.push_back(reply.readStrongBinder()); + EXPECT_EQ(BpBinder::getBinderProxyCount(), ++count); + } + // Remove every other one and verify the count. + auto it = proxies.begin(); + for (size_t i = 0; it != proxies.end(); i++) { + if (i % 2 == 0) { + it = proxies.erase(it); + EXPECT_EQ(BpBinder::getBinderProxyCount(), --count); + } + } + } + EXPECT_EQ(BpBinder::getBinderProxyCount(), initialCount); +} + class BinderLibRpcTestBase : public BinderLibTest { public: void SetUp() override { @@ -1565,9 +1599,8 @@ public: } switch (code) { case BINDER_LIB_TEST_REGISTER_SERVER: { - int32_t id; sp<IBinder> binder; - id = data.readInt32(); + /*id =*/data.readInt32(); binder = data.readStrongBinder(); if (binder == nullptr) { return BAD_VALUE; @@ -1963,7 +1996,10 @@ int run_server(int index, int readypipefd, bool usePoll) if (index == 0) { ret = sm->addService(binderLibTestServiceName, testService); } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> server = sm->getService(binderLibTestServiceName); +#pragma clang diagnostic pop Parcel data, reply; data.writeInt32(index); data.writeStrongBinder(testService); diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index 6773c95ed6..d08a9bb430 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -133,7 +133,10 @@ class BinderRecordReplayTest : public ::testing::Test { public: void SetUp() override { // get the remote service +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" auto binder = defaultServiceManager()->getService(kServerName); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); mInterface = interface_cast<IBinderRecordReplayTest>(binder); mBpBinder = binder->remoteBinder(); diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 4c3c68e2e7..1340ea1d2c 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -14,7 +14,10 @@ * limitations under the License. */ +#ifndef __ANDROID_VENDOR__ +// only used on NDK tests outside of vendor #include <aidl/IBinderRpcTest.h> +#endif #include <android-base/stringprintf.h> #include <chrono> @@ -227,7 +230,7 @@ static base::unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) std::vector<std::variant<base::unique_fd, base::borrowed_fd>> fds; fds.emplace_back(std::move(sockServer)); - if (sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) { + if (binder::os::sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) { int savedErrno = errno; LOG(FATAL) << "Failed sendMessageOnSocket: " << strerror(savedErrno); } @@ -1589,7 +1592,7 @@ public: int buf; iovec iov{&buf, sizeof(buf)}; - if (receiveMessageFromSocket(mFd, &iov, 1, &fds) < 0) { + if (binder::os::receiveMessageFromSocket(mFd, &iov, 1, &fds) < 0) { int savedErrno = errno; LOG(FATAL) << "Failed receiveMessage: " << strerror(savedErrno); } diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index c1364dd9a0..eceff35e3e 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -70,12 +70,23 @@ static inline std::vector<RpcSecurity> RpcSecurityValues() { return {RpcSecurity::RAW, RpcSecurity::TLS}; } +static inline bool hasExperimentalRpc() { +#ifdef __ANDROID__ + return base::GetProperty("ro.build.version.codename", "") != "REL"; +#else + // TODO(b/305983144): restrict on other platforms + return true; +#endif +} + static inline std::vector<uint32_t> testVersions() { std::vector<uint32_t> versions; for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) { versions.push_back(i); } - versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL); + if (hasExperimentalRpc()) { + versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL); + } return versions; } diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index e43508ee79..885bb45d82 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -50,7 +50,8 @@ TEST(BinderRpc, CannotUseNextWireVersion) { TEST(BinderRpc, CanUseExperimentalWireVersion) { auto session = RpcSession::make(); - EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL)); + EXPECT_EQ(hasExperimentalRpc(), + session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL)); } TEST_P(BinderRpc, Ping) { diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp index 642cea440d..7ec7c99f06 100644 --- a/libs/binder/tests/binderRpcWireProtocolTest.cpp +++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include <android-base/hex.h> #include <android-base/logging.h> #include <android-base/macros.h> #include <android-base/properties.h> @@ -25,6 +24,7 @@ #include <gtest/gtest.h> #include "../Debug.h" +#include "../Utils.h" namespace android { @@ -176,7 +176,7 @@ static std::string buildRepr(uint32_t version) { setParcelForRpc(&p, version); kFillFuns[i](&p); - result += base::HexString(p.data(), p.dataSize()); + result += HexString(p.data(), p.dataSize()); } return result; } @@ -263,16 +263,4 @@ TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) { } } -TEST(RpcWire, IfNotExperimentalCodeHasNoExperimentalFeatures) { - if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { - GTEST_SKIP() << "Version is experimental, so experimental features are okay."; - } - - // if we set the wire protocol version to experimental, none of the code - // should introduce a difference (if this fails, it means we have features - // which are enabled under experimental mode, but we aren't actually using - // or testing them!) - checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL); -} - } // namespace android diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index 5e8a32a61b..1c13866626 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -605,7 +605,10 @@ private: static constexpr const char* getLogTag() { return "SafeInterfaceTest"; } sp<ISafeInterfaceTest> getRemoteService() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> binder = defaultServiceManager()->getService(kServiceName); +#pragma clang diagnostic pop sp<ISafeInterfaceTest> iface = interface_cast<ISafeInterfaceTest>(binder); EXPECT_TRUE(iface != nullptr); diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp index 2398e1e1ef..3d993588a4 100644 --- a/libs/binder/tests/binderStabilityTest.cpp +++ b/libs/binder/tests/binderStabilityTest.cpp @@ -155,7 +155,10 @@ TEST(BinderStability, NdkForceDowngradeToLocalStability) { } TEST(BinderStability, ForceDowngradeToVendorStability) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); +#pragma clang diagnostic pop auto server = interface_cast<IBinderStabilityTest>(serverBinder); ASSERT_NE(nullptr, server.get()); @@ -206,7 +209,10 @@ TEST(BinderStability, ConnectionInfoRequiresManifestEntries) { EXPECT_EQ(connectionInfo, std::nullopt); } TEST(BinderStability, CantCallVendorBinderInSystemContext) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); +#pragma clang diagnostic pop auto server = interface_cast<IBinderStabilityTest>(serverBinder); ASSERT_NE(nullptr, server.get()); @@ -310,8 +316,11 @@ static AIBinder_Class* kNdkBadStableBinder = extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY TEST(BinderStability, NdkCantCallVendorBinderInSystemContext) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" SpAIBinder binder = SpAIBinder(AServiceManager_getService( String8(kSystemStabilityServer).c_str())); +#pragma clang diagnostic pop std::shared_ptr<aidl::IBinderStabilityTest> remoteServer = aidl::IBinderStabilityTest::fromBinder(binder); diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp index cfaf2a987f..0ea4a3faaa 100644 --- a/libs/binder/tests/binderThroughputTest.cpp +++ b/libs/binder/tests/binderThroughputTest.cpp @@ -204,7 +204,10 @@ void worker_fx(int num, for (int i = 0; i < server_count; i++) { if (num == i) continue; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" workers.push_back(serviceMgr->getService(generateServiceName(i))); +#pragma clang diagnostic pop } // Run the benchmark if client diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp index 46d387ce86..416ffad466 100644 --- a/libs/binder/tests/parcel_fuzzer/binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder.cpp @@ -21,14 +21,15 @@ #include "parcelables/SingleDataParcelable.h" #include "util.h" -#include <android-base/hex.h> #include <android/os/IServiceManager.h> #include <binder/ParcelableHolder.h> #include <binder/PersistableBundle.h> #include <binder/Status.h> +#include "../../Utils.h" + using ::android::status_t; -using ::android::base::HexString; +using ::android::HexString; enum ByteEnum : int8_t {}; enum IntEnum : int32_t {}; diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp index 438e8ae9b2..cdc8bccf0c 100644 --- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp +++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp @@ -18,12 +18,13 @@ #include "hwbinder.h" #include "util.h" -#include <android-base/hex.h> #include <android-base/logging.h> #include <hwbinder/Parcel.h> +#include "../../Utils.h" + using ::android::status_t; -using ::android::base::HexString; +using ::android::HexString; // TODO: support scatter-gather types diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h index 5755239c8b..071250ddf1 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h @@ -15,7 +15,6 @@ */ #include <android-base/file.h> -#include <android-base/hex.h> #include <android-base/logging.h> #include <binder/Binder.h> @@ -27,7 +26,6 @@ #include <vector> using android::Parcel; -using android::base::HexString; using std::vector; namespace android { diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp index bef4ab6e99..5b1e9eac23 100644 --- a/libs/binder/tests/parcel_fuzzer/main.cpp +++ b/libs/binder/tests/parcel_fuzzer/main.cpp @@ -22,7 +22,6 @@ #include <iostream> -#include <android-base/hex.h> #include <android-base/logging.h> #include <android/binder_auto_utils.h> #include <android/binder_libbinder.h> @@ -34,10 +33,12 @@ #include <sys/resource.h> #include <sys/time.h> +#include "../../Utils.h" + using android::fillRandomParcel; using android::RandomParcelOptions; using android::sp; -using android::base::HexString; +using android::HexString; void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) { diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp index 7390d497c4..4a9bd07c6e 100644 --- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp @@ -51,7 +51,9 @@ std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) { int flags = O_CLOEXEC; if (provider->ConsumeBool()) flags |= O_DIRECT; - if (provider->ConsumeBool()) flags |= O_NONBLOCK; + + // TODO(b/236812909): also test blocking + if (true) flags |= O_NONBLOCK; CHECK_EQ(0, pipe2(pipefds, flags)) << flags; diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index f0beed234b..f367b419af 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -66,6 +66,11 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti }, // write FD [&]() { + // b/296516864 - Limit number of objects written to a parcel. + if (p->objectsCount() > 100) { + return; + } + if (options->extraFds.size() > 0 && provider.ConsumeBool()) { const base::unique_fd& fd = options->extraFds.at( provider.ConsumeIntegralInRange<size_t>(0, @@ -82,7 +87,6 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti CHECK(OK == p->writeFileDescriptor(fds.begin()->release(), true /*takeOwnership*/)); - options->extraFds.insert(options->extraFds.end(), std::make_move_iterator(fds.begin() + 1), std::make_move_iterator(fds.end())); @@ -90,6 +94,11 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti }, // write binder [&]() { + // b/296516864 - Limit number of objects written to a parcel. + if (p->objectsCount() > 100) { + return; + } + sp<IBinder> binder; if (options->extraBinders.size() > 0 && provider.ConsumeBool()) { binder = options->extraBinders.at( diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp index 0035e4ee5a..d3cd528e26 100644 --- a/libs/binder/tests/schd-dbg.cpp +++ b/libs/binder/tests/schd-dbg.cpp @@ -340,7 +340,10 @@ void worker_fx(int num, int no_process, int iterations, int payload_size, for (int i = 0; i < server_count; i++) { // self service is in-process so just skip if (num == i) continue; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" workers.push_back(serviceMgr->getService(generateServiceName(i))); +#pragma clang diagnostic pop } // Client for each pair iterates here diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h index 5079431058..0a584bfe56 100644 --- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h +++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h @@ -26,7 +26,6 @@ #include <binder/Parcel.h> #include <binder/Stability.h> -#include <cutils/compiler.h> #include <utils/KeyedVector.h> #include <utils/Log.h> #include <utils/Mutex.h> diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h index bf7c61347f..a6dc182588 100644 --- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h +++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h @@ -23,7 +23,6 @@ #include <binder/IResultReceiver.h> #include <binder/Parcel.h> #include <binder/Stability.h> -#include <cutils/compiler.h> #include <utils/KeyedVector.h> #include <utils/Log.h> #include <utils/Mutex.h> diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index 8ec982345d..43e06e013d 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -28,7 +28,7 @@ using android::base::Result; -namespace android { +namespace android::binder::os { Result<void> setNonBlocking(android::base::borrowed_fd /*fd*/) { // Trusty IPC syscalls are all non-blocking by default. @@ -73,4 +73,4 @@ ssize_t receiveMessageFromSocket( return -1; } -} // namespace android +} // namespace android::binder::os diff --git a/libs/binder/trusty/fuzzer/Android.bp b/libs/binder/trusty/fuzzer/Android.bp index 2f1f54b0a6..4f9b5c4d9d 100644 --- a/libs/binder/trusty/fuzzer/Android.bp +++ b/libs/binder/trusty/fuzzer/Android.bp @@ -24,6 +24,7 @@ cc_fuzz { "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"", "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"", "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=1", ], } @@ -35,5 +36,30 @@ cc_fuzz { "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"", "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"", "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=1", + ], +} + +cc_fuzz { + name: "trusty_binder_fuzzer_multi_connection", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"", + "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"", + "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=10", + ], +} + +cc_fuzz { + name: "trusty_binder_rpc_fuzzer_multi_connection", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"", + "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"", + "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=10", ], } diff --git a/libs/binder/trusty/kernel/rules.mk b/libs/binder/trusty/kernel/rules.mk index ab7a50d3f7..1f05ef757a 100644 --- a/libs/binder/trusty/kernel/rules.mk +++ b/libs/binder/trusty/kernel/rules.mk @@ -31,28 +31,22 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/FdTrigger.cpp \ $(LIBBINDER_DIR)/IInterface.cpp \ $(LIBBINDER_DIR)/IResultReceiver.cpp \ + $(LIBBINDER_DIR)/OS_android.cpp \ $(LIBBINDER_DIR)/Parcel.cpp \ $(LIBBINDER_DIR)/Stability.cpp \ $(LIBBINDER_DIR)/Status.cpp \ $(LIBBINDER_DIR)/Utils.cpp \ $(LIBBASE_DIR)/hex.cpp \ $(LIBBASE_DIR)/stringprintf.cpp \ - $(LIBUTILS_DIR)/Errors.cpp \ + $(LIBUTILS_DIR)/binder/Errors.cpp \ + $(LIBUTILS_DIR)/binder/RefBase.cpp \ + $(LIBUTILS_DIR)/binder/SharedBuffer.cpp \ + $(LIBUTILS_DIR)/binder/String16.cpp \ + $(LIBUTILS_DIR)/binder/String8.cpp \ + $(LIBUTILS_DIR)/binder/StrongPointer.cpp \ + $(LIBUTILS_DIR)/binder/Unicode.cpp \ + $(LIBUTILS_DIR)/binder/VectorImpl.cpp \ $(LIBUTILS_DIR)/misc.cpp \ - $(LIBUTILS_DIR)/RefBase.cpp \ - $(LIBUTILS_DIR)/StrongPointer.cpp \ - $(LIBUTILS_DIR)/Unicode.cpp \ - -# TODO: remove the following when libbinder supports std::string -# instead of String16 and String8 for Status and descriptors -MODULE_SRCS += \ - $(LIBUTILS_DIR)/SharedBuffer.cpp \ - $(LIBUTILS_DIR)/String16.cpp \ - $(LIBUTILS_DIR)/String8.cpp \ - -# TODO: disable dump() transactions to get rid of Vector -MODULE_SRCS += \ - $(LIBUTILS_DIR)/VectorImpl.cpp \ MODULE_DEFINES += \ LK_DEBUGLEVEL_NO_ALIASES=1 \ diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk index 42db29a2ef..2e56cbd21b 100644 --- a/libs/binder/trusty/rules.mk +++ b/libs/binder/trusty/rules.mk @@ -35,6 +35,7 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/FdTrigger.cpp \ $(LIBBINDER_DIR)/IInterface.cpp \ $(LIBBINDER_DIR)/IResultReceiver.cpp \ + $(LIBBINDER_DIR)/OS_android.cpp \ $(LIBBINDER_DIR)/Parcel.cpp \ $(LIBBINDER_DIR)/ParcelFileDescriptor.cpp \ $(LIBBINDER_DIR)/RpcServer.cpp \ @@ -45,22 +46,15 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/Utils.cpp \ $(LIBBASE_DIR)/hex.cpp \ $(LIBBASE_DIR)/stringprintf.cpp \ - $(LIBUTILS_DIR)/Errors.cpp \ + $(LIBUTILS_DIR)/binder/Errors.cpp \ + $(LIBUTILS_DIR)/binder/RefBase.cpp \ + $(LIBUTILS_DIR)/binder/SharedBuffer.cpp \ + $(LIBUTILS_DIR)/binder/String16.cpp \ + $(LIBUTILS_DIR)/binder/String8.cpp \ + $(LIBUTILS_DIR)/binder/StrongPointer.cpp \ + $(LIBUTILS_DIR)/binder/Unicode.cpp \ + $(LIBUTILS_DIR)/binder/VectorImpl.cpp \ $(LIBUTILS_DIR)/misc.cpp \ - $(LIBUTILS_DIR)/RefBase.cpp \ - $(LIBUTILS_DIR)/StrongPointer.cpp \ - $(LIBUTILS_DIR)/Unicode.cpp \ - -# TODO: remove the following when libbinder supports std::string -# instead of String16 and String8 for Status and descriptors -MODULE_SRCS += \ - $(LIBUTILS_DIR)/SharedBuffer.cpp \ - $(LIBUTILS_DIR)/String16.cpp \ - $(LIBUTILS_DIR)/String8.cpp \ - -# TODO: disable dump() transactions to get rid of Vector -MODULE_SRCS += \ - $(LIBUTILS_DIR)/VectorImpl.cpp \ MODULE_EXPORT_INCLUDES += \ $(LOCAL_DIR)/include \ diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 16315ed858..ed5d5c1095 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -138,6 +138,16 @@ static const std::string getSystemNativeLibraries(NativeLibrary type) { return base::Join(soNames, ':'); } +static sp<IGpuService> getGpuService() { + static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu")); + if (!binder) { + ALOGE("Failed to get gpu service"); + return nullptr; + } + + return interface_cast<IGpuService>(binder); +} + /*static*/ GraphicsEnv& GraphicsEnv::getInstance() { static GraphicsEnv env; return env; @@ -160,8 +170,12 @@ bool GraphicsEnv::isDebuggable() { return appDebuggable || platformDebuggable; } -void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path, - const std::string sphalLibraries) { +/** + * APIs for updatable graphics drivers + */ + +void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string& path, + const std::string& sphalLibraries) { if (!mDriverPath.empty() || !mSphalLibraries.empty()) { ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries " "from '%s' to '%s'", @@ -174,6 +188,108 @@ void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path, mSphalLibraries = sphalLibraries; } +// Return true if all the required libraries from vndk and sphal namespace are +// linked to the driver namespace correctly. +bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace, + android_namespace_t* vndkNamespace, + const std::string& sharedSphalLibraries) { + const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); + if (llndkLibraries.empty()) { + return false; + } + if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) { + ALOGE("Failed to link default namespace[%s]", dlerror()); + return false; + } + + const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP); + if (vndkspLibraries.empty()) { + return false; + } + if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) { + ALOGE("Failed to link vndk namespace[%s]", dlerror()); + return false; + } + + if (sharedSphalLibraries.empty()) { + return true; + } + + // Make additional libraries in sphal to be accessible + auto sphalNamespace = android_get_exported_namespace("sphal"); + if (!sphalNamespace) { + ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace", + sharedSphalLibraries.c_str()); + return false; + } + + if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) { + ALOGE("Failed to link sphal namespace[%s]", dlerror()); + return false; + } + + return true; +} + +android_namespace_t* GraphicsEnv::getDriverNamespace() { + std::lock_guard<std::mutex> lock(mNamespaceMutex); + + if (mDriverNamespace) { + return mDriverNamespace; + } + + if (mDriverPath.empty()) { + // 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") != 0) { + return nullptr; + } + const sp<IGpuService> 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"); + if (!vndkNamespace) { + return nullptr; + } + + mDriverNamespace = android_create_namespace("updatable gfx driver", + mDriverPath.c_str(), // ld_library_path + mDriverPath.c_str(), // default_library_path + ANDROID_NAMESPACE_TYPE_ISOLATED, + nullptr, // permitted_when_isolated_path + nullptr); + + if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) { + mDriverNamespace = nullptr; + } + + return mDriverNamespace; +} + +std::string GraphicsEnv::getDriverPath() const { + return mDriverPath; +} + +/** + * APIs for GpuStats + */ + void GraphicsEnv::hintActivityLaunch() { ATRACE_CALL(); @@ -328,16 +444,6 @@ void GraphicsEnv::setVulkanDeviceExtensions(uint32_t enabledExtensionCount, extensionHashes, numStats); } -static sp<IGpuService> getGpuService() { - static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu")); - if (!binder) { - ALOGE("Failed to get gpu service"); - return nullptr; - } - - return interface_cast<IGpuService>(binder); -} - bool GraphicsEnv::readyToSendGpuStatsLocked() { // Only send stats for processes having at least one activity launched and that process doesn't // skip the GraphicsEnvironment setup. @@ -410,198 +516,97 @@ bool GraphicsEnv::setInjectLayersPrSetDumpable() { return true; } -void* GraphicsEnv::loadLibrary(std::string name) { - const android_dlextinfo dlextinfo = { - .flags = ANDROID_DLEXT_USE_NAMESPACE, - .library_namespace = getAngleNamespace(), - }; - - std::string libName = std::string("lib") + name + "_angle.so"; - - void* so = android_dlopen_ext(libName.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); - - if (so) { - ALOGD("dlopen_ext from APK (%s) success at %p", libName.c_str(), so); - return so; - } else { - ALOGE("dlopen_ext(\"%s\") failed: %s", libName.c_str(), dlerror()); - } - - return nullptr; -} - -bool GraphicsEnv::shouldUseAngle(std::string appName) { - if (appName != mAngleAppName) { - // Make sure we are checking the app we were init'ed for - ALOGE("App name does not match: expected '%s', got '%s'", mAngleAppName.c_str(), - appName.c_str()); - return false; - } - - return shouldUseAngle(); -} +/** + * APIs for ANGLE + */ bool GraphicsEnv::shouldUseAngle() { // Make sure we are init'ed - if (mAngleAppName.empty()) { - ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE."); + if (mPackageName.empty()) { + ALOGV("Package name is empty. setAngleInfo() has not been called to enable ANGLE."); return false; } - return (mUseAngle == YES) ? true : false; + return mShouldUseAngle; } -void GraphicsEnv::updateUseAngle() { - const char* ANGLE_PREFER_ANGLE = "angle"; - const char* ANGLE_PREFER_NATIVE = "native"; - - mUseAngle = NO; - if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { - ALOGV("User set \"Developer Options\" to force the use of ANGLE"); - mUseAngle = YES; - } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { - ALOGV("User set \"Developer Options\" to force the use of Native"); - } else { - ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str()); - } -} - -void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName, - const std::string developerOptIn, +// Set ANGLE information. +// If path is "system", it means system ANGLE must be used for the process. +// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. +// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, + const std::string& packageName, const std::vector<std::string> eglFeatures) { - if (mUseAngle != UNKNOWN) { - // We've already figured out an answer for this app, so just return. - ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(), - (mUseAngle == YES) ? "true" : "false"); + if (mShouldUseAngle) { + // ANGLE is already set up for this application process, even if the application + // needs to switch from apk to system or vice versa, the application process must + // be killed and relaunch so that the loader can properly load ANGLE again. + // The architecture does not support runtime switch between drivers, so just return. + ALOGE("ANGLE is already set for %s", packageName.c_str()); return; } mAngleEglFeatures = std::move(eglFeatures); - ALOGV("setting ANGLE path to '%s'", path.c_str()); - mAnglePath = path; - ALOGV("setting ANGLE app name to '%s'", appName.c_str()); - mAngleAppName = appName; - ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str()); - mAngleDeveloperOptIn = developerOptIn; - - // Update the current status of whether we should use ANGLE or not - updateUseAngle(); -} - -void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) { - if (mLayerPaths.empty()) { - mLayerPaths = layerPaths; - mAppNamespace = appNamespace; - } else { - ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'", - layerPaths.c_str(), appNamespace); + mAnglePath = std::move(path); + ALOGV("setting app package name to '%s'", packageName.c_str()); + mPackageName = std::move(packageName); + if (mAnglePath == "system") { + mShouldUseSystemAngle = true; } + if (!mAnglePath.empty()) { + mShouldUseAngle = true; + } + mShouldUseNativeDriver = shouldUseNativeDriver; } -NativeLoaderNamespace* GraphicsEnv::getAppNamespace() { - return mAppNamespace; -} - -std::string& GraphicsEnv::getAngleAppName() { - return mAngleAppName; +std::string& GraphicsEnv::getPackageName() { + return mPackageName; } const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() { return mAngleEglFeatures; } -const std::string& GraphicsEnv::getLayerPaths() { - return mLayerPaths; -} - -const std::string& GraphicsEnv::getDebugLayers() { - return mDebugLayers; -} - -const std::string& GraphicsEnv::getDebugLayersGLES() { - return mDebugLayersGLES; -} - -void GraphicsEnv::setDebugLayers(const std::string layers) { - mDebugLayers = layers; -} - -void GraphicsEnv::setDebugLayersGLES(const std::string layers) { - mDebugLayersGLES = layers; -} - -// Return true if all the required libraries from vndk and sphal namespace are -// linked to the updatable gfx driver namespace correctly. -bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) { - const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); - if (llndkLibraries.empty()) { - return false; - } - if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) { - ALOGE("Failed to link default namespace[%s]", dlerror()); - return false; - } - - const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP); - if (vndkspLibraries.empty()) { - return false; - } - if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) { - ALOGE("Failed to link vndk namespace[%s]", dlerror()); - return false; - } - - if (mSphalLibraries.empty()) { - return true; - } +android_namespace_t* GraphicsEnv::getAngleNamespace() { + std::lock_guard<std::mutex> lock(mNamespaceMutex); - // Make additional libraries in sphal to be accessible - auto sphalNamespace = android_get_exported_namespace("sphal"); - if (!sphalNamespace) { - ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace", - mSphalLibraries.c_str()); - return false; + if (mAngleNamespace) { + return mAngleNamespace; } - if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) { - ALOGE("Failed to link sphal namespace[%s]", dlerror()); - return false; + if (mAnglePath.empty() && !mShouldUseSystemAngle) { + ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace"); + return nullptr; } - return true; -} + // Construct the search paths for system ANGLE. + const char* const defaultLibraryPaths = +#if defined(__LP64__) + "/vendor/lib64/egl:/system/lib64/egl"; +#else + "/vendor/lib/egl:/system/lib/egl"; +#endif -android_namespace_t* GraphicsEnv::getDriverNamespace() { - std::lock_guard<std::mutex> lock(mNamespaceMutex); + // If the application process will run on top of system ANGLE, construct the namespace + // with sphal namespace being the parent namespace so that search paths and libraries + // are properly inherited. + mAngleNamespace = + android_create_namespace("ANGLE", + mShouldUseSystemAngle ? defaultLibraryPaths + : mAnglePath.c_str(), // ld_library_path + mShouldUseSystemAngle + ? defaultLibraryPaths + : mAnglePath.c_str(), // default_library_path + ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED, + nullptr, // permitted_when_isolated_path + mShouldUseSystemAngle ? android_get_exported_namespace("sphal") + : nullptr); // parent - if (mDriverNamespace) { - return mDriverNamespace; - } + ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default"); - if (mDriverPath.empty()) { - // 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<IGpuService> 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()); + if (!mShouldUseSystemAngle) { + return mAngleNamespace; } auto vndkNamespace = android_get_exported_namespace("vndk"); @@ -609,55 +614,67 @@ android_namespace_t* GraphicsEnv::getDriverNamespace() { return nullptr; } - mDriverNamespace = android_create_namespace("gfx driver", - mDriverPath.c_str(), // ld_library_path - mDriverPath.c_str(), // default_library_path - ANDROID_NAMESPACE_TYPE_ISOLATED, - nullptr, // permitted_when_isolated_path - nullptr); + if (!linkDriverNamespaceLocked(mAngleNamespace, vndkNamespace, "")) { + mAngleNamespace = nullptr; + } - if (!linkDriverNamespaceLocked(vndkNamespace)) { - mDriverNamespace = nullptr; + return mAngleNamespace; +} + +void GraphicsEnv::nativeToggleAngleAsSystemDriver(bool enabled) { + const sp<IGpuService> gpuService = getGpuService(); + if (!gpuService) { + ALOGE("No GPU service"); + return; } + gpuService->toggleAngleAsSystemDriver(enabled); +} - return mDriverNamespace; +bool GraphicsEnv::shouldUseSystemAngle() { + return mShouldUseSystemAngle; } -std::string GraphicsEnv::getDriverPath() const { - return mDriverPath; +bool GraphicsEnv::shouldUseNativeDriver() { + return mShouldUseNativeDriver; } -android_namespace_t* GraphicsEnv::getAngleNamespace() { - std::lock_guard<std::mutex> lock(mNamespaceMutex); +/** + * APIs for debuggable layers + */ - if (mAngleNamespace) { - return mAngleNamespace; +void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, + const std::string& layerPaths) { + if (mLayerPaths.empty()) { + mLayerPaths = layerPaths; + mAppNamespace = appNamespace; + } else { + ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'", + layerPaths.c_str(), appNamespace); } +} - if (mAnglePath.empty()) { - ALOGV("mAnglePath is empty, not creating ANGLE namespace"); - return nullptr; - } +NativeLoaderNamespace* GraphicsEnv::getAppNamespace() { + return mAppNamespace; +} - mAngleNamespace = android_create_namespace("ANGLE", - nullptr, // ld_library_path - mAnglePath.c_str(), // default_library_path - ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED, - nullptr, // permitted_when_isolated_path - nullptr); +const std::string& GraphicsEnv::getLayerPaths() { + return mLayerPaths; +} - ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default"); +const std::string& GraphicsEnv::getDebugLayers() { + return mDebugLayers; +} - return mAngleNamespace; +const std::string& GraphicsEnv::getDebugLayersGLES() { + return mDebugLayersGLES; } -void GraphicsEnv::nativeToggleAngleAsSystemDriver(bool enabled) { - const sp<IGpuService> gpuService = getGpuService(); - if (!gpuService) { - ALOGE("No GPU service"); - return; - } - gpuService->toggleAngleAsSystemDriver(enabled); +void GraphicsEnv::setDebugLayers(const std::string& layers) { + mDebugLayers = layers; +} + +void GraphicsEnv::setDebugLayersGLES(const std::string& layers) { + mDebugLayersGLES = layers; } } // namespace android diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index f9b234a047..6cce3f6998 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -29,6 +29,11 @@ namespace android { struct NativeLoaderNamespace; +// The GraphicsEnv is a singleton per application process and is used to properly set up the +// graphics drivers for the application process during application starts. The architecture of +// the graphics driver loader does not support runtime switch and only supports switch to different +// graphics drivers when application process launches and hence the only way to switch to different +// graphics drivers is to completely kill the application process and relaunch the application. class GraphicsEnv { public: static GraphicsEnv& getInstance(); @@ -55,7 +60,7 @@ public: // Also set additional required sphal libraries to the linker for loading // 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); + void setDriverPathAndSphalLibraries(const std::string& path, const std::string& sphalLibraries); // Get the updatable driver namespace. android_namespace_t* getDriverNamespace(); std::string getDriverPath() const; @@ -96,8 +101,6 @@ public: /* * 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 @@ -105,83 +108,102 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, - const std::vector<std::string> eglFeatures); + // If the search patch is "system", then it means the system ANGLE should be used. + // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. + // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. + void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, + const std::string& packageName, const std::vector<std::string> eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); - // Get the app name for ANGLE debug message. - std::string& getAngleAppName(); - + // Get the app package name. + std::string& getPackageName(); const std::vector<std::string>& getAngleEglFeatures(); + // Set the persist.graphics.egl system property value. + void nativeToggleAngleAsSystemDriver(bool enabled); + bool shouldUseSystemAngle(); + bool shouldUseNativeDriver(); /* * Apis for debug layer */ // Set additional layer search paths. - void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths); + 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); + void setDebugLayers(const std::string& layers); // Set the GL debug layers. - void setDebugLayersGLES(const std::string 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(); - // Set the persist.graphics.egl system property value. - void nativeToggleAngleAsSystemDriver(bool enabled); private: - enum UseAngle { UNKNOWN, YES, NO }; - - // Load requested ANGLE library. - void* loadLibrary(std::string name); - // Update whether ANGLE should be used. - void updateUseAngle(); // Link updatable driver namespace with llndk and vndk-sp libs. - bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace); + bool linkDriverNamespaceLocked(android_namespace_t* destNamespace, + android_namespace_t* vndkNamespace, + const std::string& sharedSphalLibraries); // Check whether this process is ready to send stats. bool readyToSendGpuStatsLocked(); // Send the initial complete GpuStats to GpuService. void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); GraphicsEnv() = default; + + // This mutex protects the namespace creation. + std::mutex mNamespaceMutex; + + /** + * Updatable driver variables. + */ // Path to updatable driver libs. std::string mDriverPath; // Path to additional sphal libs linked to updatable driver namespace. std::string mSphalLibraries; + // Updatable driver namespace. + android_namespace_t* mDriverNamespace = nullptr; + + /** + * ANGLE variables. + */ + // Path to ANGLE libs. + std::string mAnglePath; + // App's package name. + std::string mPackageName; + // ANGLE EGL features; + std::vector<std::string> mAngleEglFeatures; + // Whether ANGLE should be used. + bool mShouldUseAngle = false; + // Whether loader should load system ANGLE. + bool mShouldUseSystemAngle = false; + // Whether loader should load native GLES driver. + bool mShouldUseNativeDriver = false; + // ANGLE namespace. + android_namespace_t* mAngleNamespace = nullptr; + + /** + * GPU metrics. + */ // This mutex protects mGpuStats and get gpuservice call. std::mutex mStatsLock; // Cache the activity launch info bool mActivityLaunched = false; // 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 EGL features; - std::vector<std::string> mAngleEglFeatures; - // Use ANGLE flag. - UseAngle mUseAngle = UNKNOWN; + + /** + * Debug layers. + */ // 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. + // This App's namespace to open native libraries. NativeLoaderNamespace* mAppNamespace = nullptr; }; diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp index 3037573538..abcca345d3 100644 --- a/libs/input/MotionPredictor.cpp +++ b/libs/input/MotionPredictor.cpp @@ -176,12 +176,13 @@ std::unique_ptr<MotionEvent> MotionPredictor::predict(nsecs_t timestamp) { int64_t predictionTime = mBuffers->lastTimestamp(); const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos; - for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) { + for (size_t i = 0; i < static_cast<size_t>(predictedR.size()) && predictionTime <= futureTime; + ++i) { const TfLiteMotionPredictorSample::Point point = convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]); // TODO(b/266747654): Stop predictions if confidence is < some threshold. - ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, point.x, point.y); + ALOGD_IF(isDebug(), "prediction %zu: %f, %f", i, point.x, point.y); PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, point.x); diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp index 85fa176129..8d10ff56b0 100644 --- a/libs/input/TfLiteMotionPredictor.cpp +++ b/libs/input/TfLiteMotionPredictor.cpp @@ -115,8 +115,7 @@ std::span<T> getTensorBuffer(typename std::conditional<std::is_const<T>::value, tensor->name, TfLiteTypeGetName(tensor->type), TfLiteTypeGetName(type)); LOG_ALWAYS_FATAL_IF(!tensor->data.data); - return {reinterpret_cast<T*>(tensor->data.data), - static_cast<typename std::span<T>::index_type>(tensor->bytes / sizeof(T))}; + return std::span<T>(reinterpret_cast<T*>(tensor->data.data), tensor->bytes / sizeof(T)); } // Verifies that a tensor exists and has an underlying buffer of type T. diff --git a/libs/input/tests/TfLiteMotionPredictor_test.cpp b/libs/input/tests/TfLiteMotionPredictor_test.cpp index b5ed9e4430..c3ac0b7cfb 100644 --- a/libs/input/tests/TfLiteMotionPredictor_test.cpp +++ b/libs/input/tests/TfLiteMotionPredictor_test.cpp @@ -130,19 +130,19 @@ TEST(TfLiteMotionPredictorTest, ModelInputOutputLength) { std::unique_ptr<TfLiteMotionPredictorModel> model = TfLiteMotionPredictorModel::create(); ASSERT_GT(model->inputLength(), 0u); - const int inputLength = model->inputLength(); - ASSERT_EQ(inputLength, model->inputR().size()); - ASSERT_EQ(inputLength, model->inputPhi().size()); - ASSERT_EQ(inputLength, model->inputPressure().size()); - ASSERT_EQ(inputLength, model->inputOrientation().size()); - ASSERT_EQ(inputLength, model->inputTilt().size()); + const size_t inputLength = model->inputLength(); + ASSERT_EQ(inputLength, static_cast<size_t>(model->inputR().size())); + ASSERT_EQ(inputLength, static_cast<size_t>(model->inputPhi().size())); + ASSERT_EQ(inputLength, static_cast<size_t>(model->inputPressure().size())); + ASSERT_EQ(inputLength, static_cast<size_t>(model->inputOrientation().size())); + ASSERT_EQ(inputLength, static_cast<size_t>(model->inputTilt().size())); ASSERT_TRUE(model->invoke()); - const int outputLength = model->outputLength(); - ASSERT_EQ(outputLength, model->outputR().size()); - ASSERT_EQ(outputLength, model->outputPhi().size()); - ASSERT_EQ(outputLength, model->outputPressure().size()); + const size_t outputLength = model->outputLength(); + ASSERT_EQ(outputLength, static_cast<size_t>(model->outputR().size())); + ASSERT_EQ(outputLength, static_cast<size_t>(model->outputPhi().size())); + ASSERT_EQ(outputLength, static_cast<size_t>(model->outputPressure().size())); } TEST(TfLiteMotionPredictorTest, ModelOutput) { diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING index 3d7f3c28f4..bbad757a48 100644 --- a/libs/nativewindow/TEST_MAPPING +++ b/libs/nativewindow/TEST_MAPPING @@ -3,5 +3,13 @@ { "name": "libnativewindow_test" } + ], + "postsubmit": [ + { + "name": "libnativewindow_bindgen_test" + }, + { + "name": "libnativewindow_rs-internal_test" + } ] } diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp new file mode 100644 index 0000000000..90d0a8e400 --- /dev/null +++ b/libs/nativewindow/rust/Android.bp @@ -0,0 +1,125 @@ +// Copyright (C) 2023 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 { + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + +rust_bindgen { + name: "libnativewindow_bindgen_internal", + crate_name: "nativewindow_bindgen", + wrapper_src: "sys/nativewindow_bindings.h", + source_stem: "bindings", + bindgen_flags: [ + "--constified-enum-module=AHardwareBuffer_Format", + "--bitfield-enum=AHardwareBuffer_UsageFlags", + + "--allowlist-file=.*/nativewindow/include/.*\\.h", + "--blocklist-type", + "AParcel", + "--raw-line", + "use binder::unstable_api::AParcel;", + + "--with-derive-eq", + "--with-derive-partialeq", + ], + shared_libs: [ + "libbinder_ndk", + "libnativewindow", + ], + rustlibs: [ + "libbinder_rs", + ], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", + vendor_available: true, +} + +rust_library { + name: "libnativewindow_bindgen", + crate_name: "nativewindow_bindgen", + srcs: [":libnativewindow_bindgen_internal"], + shared_libs: [ + "libbinder_ndk", + "libnativewindow", + ], + rustlibs: [ + "libbinder_rs", + ], + lints: "none", + clippy_lints: "none", + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", + vendor_available: true, +} + +rust_test { + name: "libnativewindow_bindgen_test", + srcs: [":libnativewindow_bindgen_internal"], + crate_name: "nativewindow_bindgen_test", + rustlibs: [ + "libbinder_rs", + ], + test_suites: ["general-tests"], + auto_gen_config: true, + clippy_lints: "none", + lints: "none", +} + +rust_defaults { + name: "libnativewindow_defaults", + srcs: ["src/lib.rs"], + rustlibs: [ + "libbinder_rs", + "libnativewindow_bindgen", + ], +} + +rust_library { + name: "libnativewindow_rs", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", + vendor_available: true, +} + +rust_test { + name: "libnativewindow_rs-internal_test", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + test_suites: ["general-tests"], +} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs new file mode 100644 index 0000000000..6f86c4a48f --- /dev/null +++ b/libs/nativewindow/rust/src/lib.rs @@ -0,0 +1,418 @@ +// Copyright (C) 2023 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. + +//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer + +extern crate nativewindow_bindgen as ffi; + +pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + +use binder::{ + binder_impl::{ + BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, + SerializeArray, SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG, + }, + unstable_api::{status_result, AsNative}, + StatusCode, +}; +use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel}; +use std::fmt::{self, Debug, Formatter}; +use std::mem::ManuallyDrop; +use std::ptr::{self, null_mut, NonNull}; + +/// Wrapper around an opaque C `AHardwareBuffer`. +#[derive(PartialEq, Eq)] +pub struct HardwareBuffer(NonNull<AHardwareBuffer>); + +impl HardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + pub fn is_supported( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + stride: u32, + ) -> bool { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: *buffer_desc will never be null. + let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + + status == 1 + } + + /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the + /// buffer can be used according to the usage flags specified in its description. If a buffer is + /// used in ways not compatible with its usage flags, the results are undefined and may include + /// program termination. + /// + /// Available since API level 26. + #[inline] + pub fn new( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + ) -> Option<Self> { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut ptr = ptr::null_mut(); + // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail + // and return a status, but we check it later. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) }; + + if status == 0 { + Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null"))) + } else { + None + } + } + + /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer. + /// + /// # Errors + /// + /// Will panic if buffer_ptr is null. + /// + /// # Safety + /// + /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the + /// caller uses the pointer after the created object is dropped it will cause a memory leak. + pub unsafe fn from_raw(buffer_ptr: NonNull<AHardwareBuffer>) -> Self { + Self(buffer_ptr) + } + + /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can + /// be used to provide a pointer to the AHB for a C/C++ API over the FFI. + pub fn into_raw(self) -> NonNull<AHardwareBuffer> { + let buffer = ManuallyDrop::new(self); + buffer.0 + } + + /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme + /// and undocumented circumstances. + /// + /// Available since API level 31. + pub fn id(&self) -> u64 { + let mut out_id = 0; + // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid + // because it must have been allocated by `AHardwareBuffer_allocate`, + // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet + // released it. The id pointer must be valid because it comes from a reference. + let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ptr(), &mut out_id) }; + assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); + + out_id + } + + /// Get the width of this buffer + pub fn width(&self) -> u32 { + self.description().width + } + + /// Get the height of this buffer + pub fn height(&self) -> u32 { + self.description().height + } + + /// Get the number of layers of this buffer + pub fn layers(&self) -> u32 { + self.description().layers + } + + /// Get the format of this buffer + pub fn format(&self) -> AHardwareBuffer_Format::Type { + self.description().format + } + + /// Get the usage bitvector of this buffer + pub fn usage(&self) -> AHardwareBuffer_UsageFlags { + AHardwareBuffer_UsageFlags(self.description().usage) + } + + /// Get the stride of this buffer + pub fn stride(&self) -> u32 { + self.description().stride + } + + fn description(&self) -> ffi::AHardwareBuffer_Desc { + let mut buffer_desc = ffi::AHardwareBuffer_Desc { + width: 0, + height: 0, + layers: 0, + format: 0, + usage: 0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. + unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) }; + buffer_desc + } +} + +impl Drop for HardwareBuffer { + fn drop(&mut self) { + // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid + // because it must have been allocated by `AHardwareBuffer_allocate`, + // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet + // released it. + unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) } + } +} + +impl Debug for HardwareBuffer { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() + } +} + +impl Clone for HardwareBuffer { + fn clone(&self) -> Self { + // SAFETY: ptr is guaranteed to be non-null and the acquire can not fail. + unsafe { ffi::AHardwareBuffer_acquire(self.0.as_ptr()) }; + Self(self.0) + } +} + +impl Serialize for HardwareBuffer { + fn serialize(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { + SerializeOption::serialize_option(Some(self), parcel) + } +} + +impl SerializeOption for HardwareBuffer { + fn serialize_option( + this: Option<&Self>, + parcel: &mut BorrowedParcel, + ) -> Result<(), StatusCode> { + if let Some(this) = this { + parcel.write(&NON_NULL_PARCELABLE_FLAG)?; + + let status = + // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid + // because it must have been allocated by `AHardwareBuffer_allocate`, + // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet + // released it. + unsafe { AHardwareBuffer_writeToParcel(this.0.as_ptr(), parcel.as_native_mut()) }; + status_result(status) + } else { + parcel.write(&NULL_PARCELABLE_FLAG) + } + } +} + +impl Deserialize for HardwareBuffer { + type UninitType = Option<Self>; + + fn uninit() -> Option<Self> { + None + } + + fn from_init(value: Self) -> Option<Self> { + Some(value) + } + + fn deserialize(parcel: &BorrowedParcel) -> Result<Self, StatusCode> { + DeserializeOption::deserialize_option(parcel) + .transpose() + .unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) + } +} + +impl DeserializeOption for HardwareBuffer { + fn deserialize_option(parcel: &BorrowedParcel) -> Result<Option<Self>, StatusCode> { + let present: i32 = parcel.read()?; + match present { + NULL_PARCELABLE_FLAG => Ok(None), + NON_NULL_PARCELABLE_FLAG => { + let mut buffer = null_mut(); + + let status = + // SAFETY: Both pointers must be valid because they are obtained from references. + // `AHardwareBuffer_readFromParcel` doesn't store them or do anything else special + // with them. If it returns success then it will have allocated a new + // `AHardwareBuffer` and incremented the reference count, so we can use it until we + // release it. + unsafe { AHardwareBuffer_readFromParcel(parcel.as_native(), &mut buffer) }; + + status_result(status)?; + + Ok(Some(Self(NonNull::new(buffer).expect( + "AHardwareBuffer_readFromParcel returned success but didn't allocate buffer", + )))) + } + _ => Err(StatusCode::BAD_VALUE), + } + } +} + +impl SerializeArray for HardwareBuffer {} + +impl DeserializeArray for HardwareBuffer {} + +// SAFETY: The underlying *AHardwareBuffers can be moved between threads. +unsafe impl Send for HardwareBuffer {} + +// SAFETY: The underlying *AHardwareBuffers can be used from multiple threads. +// +// AHardwareBuffers are backed by C++ GraphicBuffers, which are mostly immutable. The only cases +// where they are not immutable are: +// +// - reallocation (which is never actually done across the codebase and requires special +// privileges/platform code access to do) +// - "locking" for reading/writing (which is explicitly allowed to be done across multiple threads +// according to the docs on the underlying gralloc calls) +unsafe impl Sync for HardwareBuffer {} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn create_valid_buffer_returns_ok() { + let buffer = HardwareBuffer::new( + 512, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ); + assert!(buffer.is_some()); + } + + #[test] + fn create_invalid_buffer_returns_err() { + let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + assert!(buffer.is_none()); + } + + #[test] + fn from_raw_allows_getters() { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width: 1024, + height: 512, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut raw_buffer_ptr = ptr::null_mut(); + + // SAFETY: The pointers are valid because they come from references, and + // `AHardwareBuffer_allocate` doesn't retain them after it returns. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; + assert_eq!(status, 0); + + // SAFETY: The pointer must be valid because it was just allocated successfully, and we + // don't use it after calling this. + let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) }; + assert_eq!(buffer.width(), 1024); + } + + #[test] + fn basic_getters() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_eq!(buffer.width(), 1024); + assert_eq!(buffer.height(), 512); + assert_eq!(buffer.layers(), 1); + assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + assert_eq!( + buffer.usage(), + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN + ); + } + + #[test] + fn id_getter() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_ne!(0, buffer.id()); + } + + #[test] + fn clone() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + assert_eq!(buffer, buffer2); + } + + #[test] + fn into_raw() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + let raw_buffer = buffer.into_raw(); + // SAFETY: This is the same pointer we had before. + let remade_buffer = unsafe { HardwareBuffer::from_raw(raw_buffer) }; + + assert_eq!(remade_buffer, buffer2); + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h new file mode 100644 index 0000000000..4525a42502 --- /dev/null +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -0,0 +1,21 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/data_space.h> +#include <android/hardware_buffer.h> +#include <android/hardware_buffer_aidl.h> +#include <android/hdr_metadata.h> +#include <android/native_window.h> diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp new file mode 100644 index 0000000000..6f844cf864 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/Android.bp @@ -0,0 +1,50 @@ +// Copyright (C) 2023 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_defaults { + name: "nativewindow_benchmark_defaults_cc", + shared_libs: ["libnativewindow"], + static_libs: [ + "libbase", + "libgoogle-benchmark-main", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +cc_benchmark { + name: "nativewindow_buffer_benchmarks_cc", + srcs: ["buffer_benchmarks.cc"], + defaults: ["nativewindow_benchmark_defaults_cc"], +} + +rust_defaults { + name: "nativewindow_benchmark_defaults_rs", + rustlibs: [ + "libnativewindow_rs", + "libcriterion", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +rust_benchmark { + name: "nativewindow_buffer_benchmarks_rs", + srcs: ["buffer_benchmarks.rs"], + defaults: ["nativewindow_benchmark_defaults_rs"], +} diff --git a/libs/nativewindow/tests/benchmark/README.md b/libs/nativewindow/tests/benchmark/README.md new file mode 100644 index 0000000000..7eae538dd2 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/README.md @@ -0,0 +1,22 @@ +# libnativewindow Benchmarks + +This directory contains benchmarks for the C++ and Rust variants of +libnativewindow. + +## Running + +It is currently a little tricky to get statistics from Rust benchmarks directly +from tradefed. But we can hack it by using atest to build/push, then running +the benchmarks by hand to get stats. + +``` + $ atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc -d + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_cc/x86_64/nativewindow_buffer_benchmarks_cc + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_rs/x86_64/nativewindow_buffer_benchmarks_rs --bench +``` + +## Results + +On a remote emulator, the results we see from the benchmarks from Rust and C++ +seem to be roughly equivalent! Allocating/deallocating a 720p buffer takes +~2.3ms on each. diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc new file mode 100644 index 0000000000..9b31993809 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <android-base/macros.h> +#include <android/hardware_buffer.h> +#include <benchmark/benchmark.h> + +constexpr AHardwareBuffer_Desc k720pDesc = {.width = 1280, + .height = 720, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + .stride = 0}; + +static void BM_BufferAllocationDeallocation(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + for (auto _ : state) { + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + AHardwareBuffer_release(buffer); + buffer = nullptr; + } +} +BENCHMARK(BM_BufferAllocationDeallocation); + +static void BM_AHardwareBuffer_Id(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + uint64_t id = 0; + int status = AHardwareBuffer_getId(buffer, &id); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to get ID."); + } + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Id); + +static void BM_AHardwareBuffer_Desc(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + AHardwareBuffer_Desc desc = {}; + AHardwareBuffer_describe(buffer, &desc); + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Desc); + +BENCHMARK_MAIN(); diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs new file mode 100644 index 0000000000..876f6c8e26 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -0,0 +1,60 @@ +// Copyright (C) 2023 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. + +//! Benchmark for libnativewindow AHardwareBuffer bindings + +#![allow(dead_code)] +#![allow(missing_docs)] + +use criterion::*; +use nativewindow::*; + +#[inline] +fn create_720p_buffer() -> HardwareBuffer { + HardwareBuffer::new( + 1280, + 720, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .unwrap() +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("allocate_deallocate", |b| { + b.iter(|| { + let buffer = create_720p_buffer(); + drop(buffer); + }) + }); + + let buffer = create_720p_buffer(); + c.bench_with_input(BenchmarkId::new("id", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.id(); + }) + }); + + // This benchmark exercises getters that need to fetch data via an + // underlying call to AHardwareBuffer_describe. + c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.width(); + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS index d073e2bd46..c4de58a517 100644 --- a/libs/vibrator/OWNERS +++ b/libs/vibrator/OWNERS @@ -1 +1,2 @@ +# Bug component: 345036 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 2c3ce16f66..04e2fffaef 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -41,24 +41,44 @@ namespace android { /* * EGL userspace drivers must be provided either: * - as a single library: - * /vendor/lib/egl/libGLES.so + * /vendor/${LIB}/egl/libGLES.so * * - as separate libraries: - * /vendor/lib/egl/libEGL.so - * /vendor/lib/egl/libGLESv1_CM.so - * /vendor/lib/egl/libGLESv2.so + * /vendor/${LIB}/egl/libEGL.so + * /vendor/${LIB}/egl/libGLESv1_CM.so + * /vendor/${LIB}/egl/libGLESv2.so * * For backward compatibility and to facilitate the transition to * this new naming scheme, the loader will additionally look for: * - * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so + * /vendor/${LIB}/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_${SUFFIX}.so * */ -Loader& Loader::getInstance() { - static Loader loader; - return loader; -} +#ifndef SYSTEM_LIB_PATH +#if defined(__LP64__) +#define SYSTEM_LIB_PATH "/system/lib64" +#else +#define SYSTEM_LIB_PATH "/system/lib" +#endif +#endif + +static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl"; +static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; +static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform"; + +static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { + PERSIST_DRIVER_SUFFIX_PROPERTY, + RO_DRIVER_SUFFIX_PROPERTY, + RO_BOARD_PLATFORM_PROPERTY, +}; + +static const char* const VENDOR_LIB_EGL_DIR = +#if defined(__LP64__) + "/vendor/lib64/egl"; +#else + "/vendor/lib/egl"; +#endif static void* do_dlopen(const char* path, int mode) { ATRACE_CALL(); @@ -80,6 +100,17 @@ static int do_android_unload_sphal_library(void* dso) { return android_unload_sphal_library(dso); } +static void* load_wrapper(const char* path) { + void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL); + ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); + return so; +} + +Loader& Loader::getInstance() { + static Loader loader; + return loader; +} + Loader::driver_t::driver_t(void* gles) { dso[0] = gles; @@ -123,37 +154,30 @@ Loader::Loader() Loader::~Loader() { } -static void* load_wrapper(const char* path) { - void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL); - ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); - return so; -} - -#ifndef EGL_WRAPPER_DIR -#if defined(__LP64__) -#define EGL_WRAPPER_DIR "/system/lib64" -#else -#define EGL_WRAPPER_DIR "/system/lib" -#endif -#endif - -static const char* DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; - -static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { - "persist.graphics.egl", - DRIVER_SUFFIX_PROPERTY, - "ro.board.platform", -}; - +// Check whether the loaded system drivers should be unloaded in order to +// load ANGLE or the updatable graphics drivers. +// If ANGLE namespace is set, it means the application is identified to run on top of ANGLE. +// If updatable graphics driver namespace is set, it means the application is identified to +// run on top of updatable graphics drivers. static bool should_unload_system_driver(egl_connection_t* cnx) { // Return false if the system driver has been unloaded once. if (cnx->systemDriverUnloaded) { return false; } - // Return true if Angle namespace is set. + // Return true if ANGLE namespace is set. android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); if (ns) { + // Unless the default GLES driver is ANGLE and the process should use system ANGLE, since + // the intended GLES driver is already loaded. + // This should be updated in a later patch that cleans up namespaces + if (!(cnx->angleLoaded && android::GraphicsEnv::getInstance().shouldUseSystemAngle())) { + return true; + } + } + + // Return true if native GLES drivers should be used and ANGLE is already loaded. + if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { return true; } @@ -199,17 +223,17 @@ void Loader::unload_system_driver(egl_connection_t* cnx) { do_android_unload_sphal_library(hnd->dso[0]); } cnx->dso = nullptr; + cnx->angleLoaded = false; } cnx->systemDriverUnloaded = true; } -void* Loader::open(egl_connection_t* cnx) -{ +void* Loader::open(egl_connection_t* cnx) { ATRACE_CALL(); const nsecs_t openTime = systemTime(); - if (should_unload_system_driver(cnx)) { + if (cnx->dso && should_unload_system_driver(cnx)) { unload_system_driver(cnx); } @@ -218,22 +242,38 @@ void* Loader::open(egl_connection_t* cnx) return cnx->dso; } - // Firstly, try to load ANGLE driver. - driver_t* hnd = attempt_to_load_angle(cnx); + driver_t* hnd = nullptr; + // Firstly, try to load ANGLE driver, if ANGLE should be loaded and fail, abort. + if (android::GraphicsEnv::getInstance().shouldUseAngle()) { + hnd = attempt_to_load_angle(cnx); + LOG_ALWAYS_FATAL_IF(!hnd, "Failed to load ANGLE."); + } if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); + + // If updated driver apk is set but fail to load, abort here. + LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), + "couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); + } + + // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. + // If native is selected but fail to load, abort. + if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { + auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); + LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), + "Native GLES driver is selected but not specified in %s", + RO_DRIVER_SUFFIX_PROPERTY); + hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); + LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", + RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); } + // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { - // If updated driver apk is set but fail to load, abort here. - if (android::GraphicsEnv::getInstance().getDriverNamespace()) { - LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); - } - // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: @@ -245,17 +285,20 @@ void* Loader::open(egl_connection_t* cnx) continue; } hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); - if (hnd) { - break; - } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { + if (!hnd) { + ALOGD("Failed to load drivers from property %s with value %s", key, prop.c_str()); failToLoadFromDriverSuffixProperty = true; } + + // Abort regardless of whether subsequent properties are set, the value must be set + // correctly with the first property that has a value. + break; } } if (!hnd) { - // Can't find graphics driver by appending system properties, now search for the exact name - // without any suffix of the GLES userspace driver in both locations. + // Can't find graphics driver by appending the value from system properties, now search for + // the exact name without any suffix of the GLES userspace driver in both locations. // i.e.: // libGLES.so, or: // libEGL.so, libGLESv1_CM.so, libGLESv2.so @@ -274,10 +317,10 @@ void* Loader::open(egl_connection_t* cnx) false, systemTime() - openTime); } else { // init_angle_backend will check if loaded driver is ANGLE or not, - // will set cnx->useAngle appropriately. + // will set cnx->angleLoaded appropriately. // Do this here so that we use ANGLE path when driver is ANGLE (e.g. loaded as native), // not just loading ANGLE as option. - init_angle_backend(hnd->dso[2], cnx); + attempt_to_init_angle_backend(hnd->dso[2], cnx); } LOG_ALWAYS_FATAL_IF(!hnd, @@ -287,13 +330,13 @@ void* Loader::open(egl_connection_t* cnx) HAL_SUBNAME_KEY_PROPERTIES[2]); if (!cnx->libEgl) { - cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so"); + cnx->libEgl = load_wrapper(SYSTEM_LIB_PATH "/libEGL.so"); } if (!cnx->libGles1) { - cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so"); + cnx->libGles1 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv1_CM.so"); } if (!cnx->libGles2) { - cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so"); + cnx->libGles2 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv2.so"); } if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) { @@ -319,7 +362,7 @@ void Loader::close(egl_connection_t* cnx) delete hnd; cnx->dso = nullptr; - cnx->useAngle = false; + cnx->angleLoaded = false; } void Loader::init_api(void* dso, @@ -396,31 +439,19 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool class MatchFile { public: static std::string find(const char* libraryName, const bool exact) { - const char* const searchPaths[] = { -#if defined(__LP64__) - "/vendor/lib64/egl", - "/system/lib64/egl" -#else - "/vendor/lib/egl", - "/system/lib/egl" -#endif - }; - - for (auto dir : searchPaths) { - std::string absolutePath; - if (find(absolutePath, libraryName, dir, exact)) { - return absolutePath; - } + std::string absolutePath; + if (findLibPath(absolutePath, libraryName, exact)) { + return absolutePath; } // Driver not found. gah. return std::string(); } private: - static bool find(std::string& result, - const std::string& pattern, const char* const search, bool exact) { + static bool findLibPath(std::string& result, const std::string& pattern, bool exact) { + const std::string vendorLibEglDirString = std::string(VENDOR_LIB_EGL_DIR); if (exact) { - std::string absolutePath = std::string(search) + "/" + pattern + ".so"; + std::string absolutePath = vendorLibEglDirString + "/" + pattern + ".so"; if (!access(absolutePath.c_str(), R_OK)) { result = absolutePath; return true; @@ -428,7 +459,7 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool return false; } - DIR* d = opendir(search); + DIR* d = opendir(VENDOR_LIB_EGL_DIR); if (d != nullptr) { struct dirent* e; while ((e = readdir(d)) != nullptr) { @@ -441,7 +472,7 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool } if (strstr(e->d_name, pattern.c_str()) == e->d_name) { if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { - result = std::string(search) + "/" + e->d_name; + result = vendorLibEglDirString + "/" + e->d_name; closedir(d); return true; } @@ -531,10 +562,6 @@ static void* load_updated_driver(const char* kind, android_namespace_t* ns) { Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { ATRACE_CALL(); - if (!android::GraphicsEnv::getInstance().shouldUseAngle()) { - return nullptr; - } - android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); if (!ns) { return nullptr; @@ -560,14 +587,14 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { return hnd; } -void Loader::init_angle_backend(void* dso, egl_connection_t* cnx) { +void Loader::attempt_to_init_angle_backend(void* dso, egl_connection_t* cnx) { void* pANGLEGetDisplayPlatform = dlsym(dso, "ANGLEGetDisplayPlatform"); if (pANGLEGetDisplayPlatform) { - ALOGV("ANGLE GLES library in use"); - cnx->useAngle = true; + ALOGV("ANGLE GLES library loaded"); + cnx->angleLoaded = true; } else { - ALOGV("Native GLES library in use"); - cnx->useAngle = false; + ALOGV("Native GLES library loaded"); + cnx->angleLoaded = false; } } diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 81742ab9ae..cadbd4639b 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -57,7 +57,7 @@ private: driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact); void unload_system_driver(egl_connection_t* cnx); void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask); - void init_angle_backend(void* dso, egl_connection_t* cnx); + void attempt_to_init_angle_backend(void* dso, egl_connection_t* cnx); static __attribute__((noinline)) void init_api(void* dso, const char* const* api, const char* const* ref_api, diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp index 7ffdac7ea7..ed3c616b92 100644 --- a/opengl/libs/EGL/MultifileBlobCache.cpp +++ b/opengl/libs/EGL/MultifileBlobCache.cpp @@ -48,9 +48,8 @@ namespace { void freeHotCacheEntry(android::MultifileHotCache& entry) { if (entry.entryFd != -1) { // If we have an fd, then this entry was added to hot cache via INIT or GET - // We need to unmap and close the entry + // We need to unmap the entry munmap(entry.entryBuffer, entry.entrySize); - close(entry.entryFd); } else { // Otherwise, this was added to hot cache during SET, so it was never mapped // and fd was only on the deferred thread. @@ -143,6 +142,7 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (result != sizeof(MultifileHeader)) { ALOGE("Error reading MultifileHeader from cache entry (%s): %s", fullPath.c_str(), std::strerror(errno)); + close(fd); return; } @@ -152,6 +152,7 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (remove(fullPath.c_str()) != 0) { ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno)); } + close(fd); continue; } @@ -161,6 +162,10 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s // Memory map the file uint8_t* mappedEntry = reinterpret_cast<uint8_t*>( mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0)); + + // We can close the file now and the mmap will remain + close(fd); + if (mappedEntry == MAP_FAILED) { ALOGE("Failed to mmap cacheEntry, error: %s", std::strerror(errno)); return; @@ -206,13 +211,11 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (!addToHotCache(entryHash, fd, mappedEntry, fileSize)) { ALOGE("INIT Failed to add %u to hot cache", entryHash); munmap(mappedEntry, fileSize); - close(fd); return; } } else { // If we're not keeping it in hot cache, unmap it now munmap(mappedEntry, fileSize); - close(fd); } } closedir(dir); @@ -401,9 +404,12 @@ EGLsizeiANDROID MultifileBlobCache::get(const void* key, EGLsizeiANDROID keySize // Memory map the file cacheEntry = reinterpret_cast<uint8_t*>(mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0)); + + // We can close the file now and the mmap will remain + close(fd); + if (cacheEntry == MAP_FAILED) { ALOGE("Failed to mmap cacheEntry, error: %s", std::strerror(errno)); - close(fd); return 0; } diff --git a/opengl/libs/EGL/MultifileBlobCache_test.cpp b/opengl/libs/EGL/MultifileBlobCache_test.cpp index dbee13bb2e..1639be6480 100644 --- a/opengl/libs/EGL/MultifileBlobCache_test.cpp +++ b/opengl/libs/EGL/MultifileBlobCache_test.cpp @@ -42,6 +42,8 @@ protected: virtual void TearDown() { mMBC.reset(); } + int getFileDescriptorCount(); + std::unique_ptr<TemporaryFile> mTempFile; std::unique_ptr<MultifileBlobCache> mMBC; }; @@ -216,4 +218,56 @@ TEST_F(MultifileBlobCacheTest, CacheMinKeyAndValueSizeSucceeds) { ASSERT_EQ('y', buf[0]); } +int MultifileBlobCacheTest::getFileDescriptorCount() { + DIR* directory = opendir("/proc/self/fd"); + + int fileCount = 0; + struct dirent* entry; + while ((entry = readdir(directory)) != NULL) { + fileCount++; + // printf("File: %s\n", entry->d_name); + } + + closedir(directory); + return fileCount; +} + +TEST_F(MultifileBlobCacheTest, EnsureFileDescriptorsClosed) { + // Populate the cache with a bunch of entries + size_t kLargeNumberOfEntries = 1024; + for (int i = 0; i < kLargeNumberOfEntries; i++) { + // printf("Caching: %i", i); + + // Use the index as the key and value + mMBC->set(&i, sizeof(i), &i, sizeof(i)); + + int result = 0; + ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result))); + ASSERT_EQ(i, result); + } + + // Ensure we don't have a bunch of open fds + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); + + // Close the cache so everything writes out + mMBC->finish(); + mMBC.reset(); + + // Now open it again and ensure we still don't have a bunch of open fds + mMBC.reset( + new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, &mTempFile->path[0])); + + // Check after initialization + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); + + for (int i = 0; i < kLargeNumberOfEntries; i++) { + int result = 0; + ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result))); + ASSERT_EQ(i, result); + } + + // And again after we've actually used it + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); +} + } // namespace android diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp index 9a6bb7a61c..ee605c2011 100644 --- a/opengl/libs/EGL/egl_angle_platform.cpp +++ b/opengl/libs/EGL/egl_angle_platform.cpp @@ -35,6 +35,7 @@ namespace angle { +constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; constexpr int kAngleDlFlags = RTLD_LOCAL | RTLD_NOW; static GetDisplayPlatformFunc angleGetDisplayPlatform = nullptr; @@ -115,8 +116,6 @@ bool initializeAnglePlatform(EGLDisplay dpy) { android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); void* so = nullptr; if (ns) { - // Loading from an APK, so hard-code the suffix to "_angle". - constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; const android_dlextinfo dlextinfo = { .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = ns, @@ -130,19 +129,11 @@ bool initializeAnglePlatform(EGLDisplay dpy) { } } else { // If we are here, ANGLE is loaded as built-in gl driver in the sphal. - // Get the specified ANGLE library filename suffix. - std::string angleEs2LibSuffix = android::base::GetProperty("ro.hardware.egl", ""); - if (angleEs2LibSuffix.empty()) { - ALOGE("%s failed to get valid ANGLE library filename suffix!", __FUNCTION__); - return false; - } - - std::string angleEs2LibName = "libGLESv2_" + angleEs2LibSuffix + ".so"; - so = android_load_sphal_library(angleEs2LibName.c_str(), kAngleDlFlags); + so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags); if (so) { - ALOGD("dlopen (%s) success at %p", angleEs2LibName.c_str(), so); + ALOGD("dlopen (%s) success at %p", kAngleEs2Lib, so); } else { - ALOGE("%s failed to dlopen %s!", __FUNCTION__, angleEs2LibName.c_str()); + ALOGE("%s failed to dlopen %s: %s!", __FUNCTION__, kAngleEs2Lib, dlerror()); return false; } } diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 525fed115d..3317347066 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -191,7 +191,7 @@ EGLDisplay egl_display_t::getPlatformDisplay(EGLNativeDisplayType display, if (cnx->dso) { EGLDisplay dpy = EGL_NO_DISPLAY; - if (cnx->useAngle) { + if (cnx->angleLoaded) { EGLint error; dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error); if (error != EGL_NONE) { @@ -324,7 +324,7 @@ EGLBoolean egl_display_t::initialize(EGLint* major, EGLint* minor) { // b/269060366 Conditionally enabled EGL_ANDROID_get_frame_timestamps extension if the // device's present timestamps are reliable (which may not be the case on emulators). - if (cnx->useAngle) { + if (cnx->angleLoaded) { if (android::base::GetBoolProperty("service.sf.present_timestamp", false)) { mExtensionString.append("EGL_ANDROID_get_frame_timestamps "); } @@ -432,7 +432,7 @@ EGLBoolean egl_display_t::terminate() { egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { // If we're using ANGLE reset any custom DisplayPlatform - if (cnx->useAngle) { + if (cnx->angleLoaded) { angle::resetAnglePlatform(disp.dpy); } if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index efbe613542..33a77c4470 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -84,7 +84,7 @@ void egl_surface_t::disconnect() { if (win != nullptr && connected) { // NOTE: When using Vulkan backend, the Vulkan runtime makes all the // native_window_* calls, so don't do them here. - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { native_window_set_buffers_format(win, 0); if (native_window_api_disconnect(win, NATIVE_WINDOW_API_EGL)) { ALOGW("EGLNativeWindowType %p disconnect failed", win); diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index aefa1f0db5..440eb17873 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -685,7 +685,7 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, // NOTE: When using Vulkan backend, the Vulkan runtime makes all the // native_window_* calls, so don't do them here. - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); if (result < 0) { ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) " @@ -704,14 +704,14 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, std::vector<AttrType> strippedAttribList; if (!processAttributes<AttrType>(dp, window, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { int err = native_window_set_buffers_format(window, static_cast<int>(format)); if (err != 0) { ALOGE("error setting native window pixel format: %s (%d)", strerror(-err), err); @@ -743,7 +743,7 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, } // EGLSurface creation failed - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { native_window_set_buffers_format(window, 0); native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } @@ -1354,7 +1354,7 @@ EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, EGLi } } - if (!s->cnx->useAngle) { + if (!s->cnx->angleLoaded) { if (!sendSurfaceMetadata(s)) { native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL); return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE); @@ -1379,7 +1379,7 @@ EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, EGLi androidRect.bottom = y; androidRects.push_back(androidRect); } - if (!s->cnx->useAngle) { + if (!s->cnx->angleLoaded) { native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), androidRects.size()); } @@ -1470,7 +1470,7 @@ EGLBoolean eglSurfaceAttribImpl(EGLDisplay dpy, EGLSurface surface, EGLint attri int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0); if (err != 0) { return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } else if (!s->cnx->useAngle) { + } else if (!s->cnx->angleLoaded) { return EGL_TRUE; } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below } @@ -1484,7 +1484,7 @@ EGLBoolean eglSurfaceAttribImpl(EGLDisplay dpy, EGLSurface surface, EGLint attri int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0); if (err != 0) { return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } else if (!s->cnx->useAngle) { + } else if (!s->cnx->angleLoaded) { return EGL_TRUE; } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below } diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h index fcc11f1b55..3bd37cb399 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -41,7 +41,8 @@ struct egl_connection_t { libEgl(nullptr), libGles1(nullptr), libGles2(nullptr), - systemDriverUnloaded(false) { + systemDriverUnloaded(false), + angleLoaded(false) { const char* const* entries = platform_names; EGLFuncPointer* curr = reinterpret_cast<EGLFuncPointer*>(&platform); while (*entries) { @@ -73,7 +74,7 @@ struct egl_connection_t { void* libGles2; bool systemDriverUnloaded; - bool useAngle; // Was ANGLE successfully loaded + bool angleLoaded; // Was ANGLE successfully loaded }; extern gl_hooks_t gHooks[2]; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 5c524d3104..901c806bea 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3900,6 +3900,16 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const std::shared_ptr<Connection>& connection, const CancelationOptions& options) { + if ((options.mode == CancelationOptions::Mode::CANCEL_POINTER_EVENTS || + options.mode == CancelationOptions::Mode::CANCEL_ALL_EVENTS) && + mDragState && mDragState->dragWindow->getToken() == connection->inputChannel->getToken()) { + LOG(INFO) << __func__ + << ": Canceling drag and drop because the pointers for the drag window are being " + "canceled."; + sendDropWindowCommandLocked(nullptr, /*x=*/0, /*y=*/0); + mDragState.reset(); + } + if (connection->status == Connection::Status::BROKEN) { return; } @@ -3924,8 +3934,13 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; InputTarget target; - sp<WindowInfoHandle> windowHandle = - getWindowHandleLocked(connection->inputChannel->getConnectionToken()); + sp<WindowInfoHandle> windowHandle; + if (options.displayId) { + windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(), + options.displayId.value()); + } else { + windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); + } if (windowHandle != nullptr) { const WindowInfo* windowInfo = windowHandle->getInfo(); target.setDefaultPointerTransform(windowInfo->transform); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 6ff420d951..f3aba79e30 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -4153,6 +4153,61 @@ TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) { } /** + * When there are multiple screens, such as screen projection to TV or screen recording, if the + * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and + * its coordinates should be converted by the transform of the windows of target screen. + */ +TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) { + // This case will create a window and a spy window on the default display and mirror + // window on the second display. cancel event is sent through spy window pilferPointers + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + + sp<FakeWindowHandle> spyWindowDefaultDisplay = + sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + spyWindowDefaultDisplay->setTrustedOverlay(true); + spyWindowDefaultDisplay->setSpy(true); + + sp<FakeWindowHandle> windowDefaultDisplay = + sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay", + ADISPLAY_ID_DEFAULT); + windowDefaultDisplay->setWindowTransform(1, 0, 0, 1); + + sp<FakeWindowHandle> windowSecondDisplay = + windowDefaultDisplay->clone(application, mDispatcher, SECOND_DISPLAY_ID); + windowSecondDisplay->setWindowTransform(2, 0, 0, 2); + + // Add the windows to the dispatcher + mDispatcher->onWindowInfosChanged( + {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(), + *windowSecondDisplay->getInfo()}, + {}, + 0, + 0}); + + // Send down to ADISPLAY_ID_DEFAULT + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + spyWindowDefaultDisplay->consumeMotionDown(); + windowDefaultDisplay->consumeMotionDown(); + + EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken())); + + // windowDefaultDisplay gets cancel + MotionEvent* event = windowDefaultDisplay->consumeMotion(); + EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction()); + + // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the + // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y + // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of + // SECOND_DISPLAY_ID, the x and y coordinates are 200 + EXPECT_EQ(100, event->getX(0)); + EXPECT_EQ(100, event->getY(0)); +} + +/** * Ensure the correct coordinate spaces are used by InputDispatcher. * * InputDispatcher works in the display space, so its coordinate system is relative to the display @@ -8697,6 +8752,75 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { mSecondWindow->assertNoEvents(); } +/** + * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag + * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash. + */ +TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) { + // Down on second window + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown()); + ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown()); + + // Down on first window + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); + ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove()); + ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1)); + + // Start drag on first window + ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN)); + + // Trigger cancel + mDispatcher->cancelCurrentTouch(); + ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel()); + ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel()); + ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel()); + + ASSERT_TRUE(mDispatcher->waitForIdle()); + // The D&D finished with nullptr + mFakePolicy->assertDropTargetEquals(nullptr); + + // Remove drag window + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0}); + + // Inject a simple gesture, ensure dispatcher not crashed + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + PointF{50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); + + const MotionEvent moveEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove()); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp()); +} + class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f12aab766e..7ea547dece 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -172,7 +172,6 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.barrierProducerId = 0; mDrawingState.bufferTransform = 0; mDrawingState.transformToDisplayInverse = false; - mDrawingState.crop.makeInvalid(); mDrawingState.acquireFence = sp<Fence>::make(-1); mDrawingState.acquireFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence); mDrawingState.dataspace = ui::Dataspace::V0_SRGB; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ee3505d7c8..343a1db265 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5438,7 +5438,6 @@ void SurfaceFlinger::initializeDisplays() { state.id = transactionId; // reset screen orientation and use primary layer stack - Vector<DisplayState> displays; DisplayState d; d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp index 2b295309e7..0b2e5a3c9d 100644 --- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp +++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp @@ -118,7 +118,7 @@ inline void PrintTo(const LayerInfo& info, ::std::ostream* os) { << info.touchableRegionBounds.right << "," << info.touchableRegionBounds.bottom << "}"; } -struct find_id : std::unary_function<LayerInfo, bool> { +struct find_id { int id; find_id(int id) : id(id) {} bool operator()(LayerInfo const& m) const { return m.id == id; } diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp index a2c54ac621..db6df229d5 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp @@ -26,8 +26,6 @@ namespace android { -using aidl::android::hardware::graphics::common::HdrConversionCapability; -using aidl::android::hardware::graphics::common::HdrConversionStrategy; using GuiHdrConversionStrategyTag = gui::HdrConversionStrategy::Tag; using gui::aidl_utils::statusTFromBinderStatus; @@ -66,17 +64,15 @@ TEST(HdrOutputControlTest, testSetHdrConversionStrategy) { sf->getHdrOutputConversionSupport(&hdrOutputConversionSupport); ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(getSupportStatus)); - std::vector<HdrConversionStrategy> strategies = - {HdrConversionStrategy(std::in_place_index<static_cast<size_t>( - GuiHdrConversionStrategyTag::passthrough)>), - HdrConversionStrategy(std::in_place_index<static_cast<size_t>( - GuiHdrConversionStrategyTag::autoAllowedHdrTypes)>), - HdrConversionStrategy(std::in_place_index<static_cast<size_t>( - GuiHdrConversionStrategyTag::forceHdrConversion)>)}; + std::vector<gui::HdrConversionStrategy> strategies = { + gui::HdrConversionStrategy::make<GuiHdrConversionStrategyTag::passthrough>(), + gui::HdrConversionStrategy::make<GuiHdrConversionStrategyTag::autoAllowedHdrTypes>(), + gui::HdrConversionStrategy::make<GuiHdrConversionStrategyTag::forceHdrConversion>(), + }; int32_t outPreferredHdrOutputType = 0; - for (HdrConversionStrategy strategy : strategies) { - binder::Status status = sf->setHdrConversionStrategy(&strategy, &outPreferredHdrOutputType); + for (const gui::HdrConversionStrategy& strategy : strategies) { + binder::Status status = sf->setHdrConversionStrategy(strategy, &outPreferredHdrOutputType); if (hdrOutputConversionSupport) { ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); |