diff options
46 files changed, 1559 insertions, 177 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index f75967451b..6dea91bc2b 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1508,7 +1508,6 @@ static void DumpCheckins(int out_fd = STDOUT_FILENO) { dprintf(out_fd, "========================================================\n"); RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd); - RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd); RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd); RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd); RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd); diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 32922ca24c..3b753c6ca4 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -44,6 +44,7 @@ cc_binary { defaults: ["servicemanager_defaults"], init_rc: ["servicemanager.rc"], srcs: ["main.cpp"], + bootstrap: true, } cc_binary { diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt index 7584ca3f53..f9f042ef5d 100644 --- a/libs/adbd_auth/libadbd_auth.map.txt +++ b/libs/adbd_auth/libadbd_auth.map.txt @@ -1,17 +1,17 @@ LIBADBD_AUTH { global: - adbd_auth_new; # apex introduced=30 - adbd_auth_delete; # apex introduced=30 - adbd_auth_run; # apex introduced=30 - adbd_auth_get_public_keys; #apex introduced=30 - adbd_auth_notify_auth; # apex introduced=30 - adbd_auth_notify_disconnect; # apex introduced=30 - adbd_auth_prompt_user; # apex introduced=30 - adbd_auth_prompt_user_with_id; # apex introduced=30 - adbd_auth_tls_device_connected; # apex introduced=30 - adbd_auth_tls_device_disconnected; # apex introduced=30 - adbd_auth_get_max_version; # apex introduced=30 - adbd_auth_supports_feature; # apex introduced=30 + adbd_auth_new; # systemapi introduced=30 + adbd_auth_delete; # systemapi introduced=30 + adbd_auth_run; # systemapi introduced=30 + adbd_auth_get_public_keys; # systemapi introduced=30 + adbd_auth_notify_auth; # systemapi introduced=30 + adbd_auth_notify_disconnect; # systemapi introduced=30 + adbd_auth_prompt_user; # systemapi introduced=30 + adbd_auth_prompt_user_with_id; # systemapi introduced=30 + adbd_auth_tls_device_connected; # systemapi introduced=30 + adbd_auth_tls_device_disconnected; # systemapi introduced=30 + adbd_auth_get_max_version; # systemapi introduced=30 + adbd_auth_supports_feature; # systemapi introduced=30 local: *; }; diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 49fc19518f..82ebdd7b0f 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -358,6 +358,14 @@ status_t BpBinder::linkToDeath( LOG_ALWAYS_FATAL_IF(recipient == nullptr, "linkToDeath(): recipient must be non-NULL"); + if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0) { + ALOGW("Linking to death on %s but there are no threads (yet?) listening to incoming " + "transactions. See ProcessState::startThreadPool and " + "ProcessState::setThreadPoolMaxThreadCount. Generally you should setup the binder " + "threadpool before other initialization steps.", + String8(getInterfaceDescriptor()).c_str()); + } + { AutoMutex _l(mLock); diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index d53621946a..b50cfb3d19 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -972,18 +972,15 @@ status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) freeBuffer); } else { err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer); - freeBuffer(nullptr, - reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), - tr.data_size, - reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(binder_size_t)); + freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), + tr.data_size, + reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), + tr.offsets_size / sizeof(binder_size_t)); } } else { - freeBuffer(nullptr, - reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), - tr.data_size, - reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), - tr.offsets_size/sizeof(binder_size_t)); + freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size, + reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets), + tr.offsets_size / sizeof(binder_size_t)); continue; } } @@ -1473,17 +1470,13 @@ void IPCThreadState::logExtendedError() { ee.id, ee.command, ee.param); } -void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data, - size_t /*dataSize*/, - const binder_size_t* /*objects*/, - size_t /*objectsSize*/) -{ +void IPCThreadState::freeBuffer(const uint8_t* data, size_t /*dataSize*/, + const binder_size_t* /*objects*/, size_t /*objectsSize*/) { //ALOGI("Freeing parcel %p", &parcel); IF_LOG_COMMANDS() { alog << "Writing BC_FREE_BUFFER for " << data << endl; } ALOG_ASSERT(data != NULL, "Called with NULL data"); - if (parcel != nullptr) parcel->closeFileDescriptors(); IPCThreadState* state = self(); state->mOut.writeInt32(BC_FREE_BUFFER); state->mOut.writePointer((uintptr_t)data); diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 537527e2c1..8b5d11800f 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2590,6 +2590,22 @@ status_t Parcel::rpcSetDataReference( LOG_ALWAYS_FATAL_IF(session == nullptr); + if (objectTableSize != ancillaryFds.size()) { + ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size()); + relFunc(data, dataSize, nullptr, 0); + return BAD_VALUE; + } + for (size_t i = 0; i < objectTableSize; i++) { + uint32_t minObjectEnd; + if (__builtin_add_overflow(objectTable[i], sizeof(RpcFields::ObjectType), &minObjectEnd) || + minObjectEnd >= dataSize) { + ALOGE("received out of range object position: %" PRIu32 " (parcel size is %zu)", + objectTable[i], dataSize); + relFunc(data, dataSize, nullptr, 0); + return BAD_VALUE; + } + } + freeData(); markForRpc(session); @@ -2600,12 +2616,6 @@ status_t Parcel::rpcSetDataReference( mDataSize = mDataCapacity = dataSize; mOwner = relFunc; - if (objectTableSize != ancillaryFds.size()) { - ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size()); - freeData(); // don't leak mData - return BAD_VALUE; - } - rpcFields->mObjectPositions.reserve(objectTableSize); for (size_t i = 0; i < objectTableSize; i++) { rpcFields->mObjectPositions.push_back(objectTable[i]); @@ -2706,7 +2716,9 @@ void Parcel::freeDataNoInit() LOG_ALLOC("Parcel %p: freeing other owner data", this); //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); auto* kernelFields = maybeKernelFields(); - mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, + // Close FDs before freeing, otherwise they will leak for kernel binder. + closeFileDescriptors(); + mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, kernelFields ? kernelFields->mObjectsSize : 0); } else { LOG_ALLOC("Parcel %p: freeing allocated data", this); @@ -2891,8 +2903,13 @@ status_t Parcel::continueWrite(size_t desired) if (objects && kernelFields && kernelFields->mObjects) { memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t)); } - //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); - mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, + // ALOGI("Freeing data ref of %p (pid=%d)", this, getpid()); + if (kernelFields) { + // TODO(b/239222407): This seems wrong. We should only free FDs when + // they are in a truncated section of the parcel. + closeFileDescriptors(); + } + mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr, kernelFields ? kernelFields->mObjectsSize : 0); mOwner = nullptr; diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 7faff47627..1f311acb20 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -19,6 +19,7 @@ #include <binder/ProcessState.h> #include <android-base/result.h> +#include <android-base/scopeguard.h> #include <android-base/strings.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> @@ -420,6 +421,9 @@ status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { } size_t ProcessState::getThreadPoolMaxTotalThreadCount() const { + pthread_mutex_lock(&mThreadCountLock); + base::ScopeGuard detachGuard = [&]() { pthread_mutex_unlock(&mThreadCountLock); }; + // may actually be one more than this, if join is called if (mThreadPoolStarted) { return mCurrentThreads < mKernelStartedThreads diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 096d5cc5ad..49be4dd9eb 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -209,9 +209,10 @@ void RpcServer::join() { { RpcMutexLockGuard _l(mLock); - RpcMaybeThread thread = RpcMaybeThread(&RpcServer::establishConnection, - sp<RpcServer>::fromExisting(this), - std::move(clientFd), addr, addrLen); + RpcMaybeThread thread = + RpcMaybeThread(&RpcServer::establishConnection, + sp<RpcServer>::fromExisting(this), std::move(clientFd), addr, + addrLen, RpcSession::join); auto& threadRef = mConnectingThreads[thread.get_id()]; threadRef = std::move(thread); @@ -294,8 +295,10 @@ size_t RpcServer::numUninitializedSessions() { return mConnectingThreads.size(); } -void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd, - std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen) { +void RpcServer::establishConnection( + sp<RpcServer>&& server, base::unique_fd clientFd, std::array<uint8_t, kRpcAddressSize> addr, + size_t addrLen, + std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn) { // mShutdownTrigger can only be cleared once connection threads have joined. // It must be set before this thread is started LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr); @@ -478,7 +481,7 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie // avoid strong cycle server = nullptr; - RpcSession::join(std::move(session), std::move(setupResult)); + joinFn(std::move(session), std::move(setupResult)); } status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) { diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 0ae75cdefa..d063001414 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -244,60 +244,63 @@ void RpcState::clear() { "New state should be impossible after terminating!"); return; } + mTerminated = true; if (SHOULD_LOG_RPC_DETAIL) { ALOGE("RpcState::clear()"); dumpLocked(); } - // if the destructor of a binder object makes another RPC call, then calling - // decStrong could deadlock. So, we must hold onto these binders until - // mNodeMutex is no longer taken. - std::vector<sp<IBinder>> tempHoldBinder; - - mTerminated = true; + // invariants for (auto& [address, node] : mNodeForAddress) { - sp<IBinder> binder = node.binder.promote(); - LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get()); - - if (node.sentRef != nullptr) { - tempHoldBinder.push_back(node.sentRef); + bool guaranteedHaveBinder = node.timesSent > 0; + if (guaranteedHaveBinder) { + LOG_ALWAYS_FATAL_IF(node.sentRef == nullptr, + "Binder expected to be owned with address: %" PRIu64 " %s", address, + node.toString().c_str()); } } - mNodeForAddress.clear(); + // if the destructor of a binder object makes another RPC call, then calling + // decStrong could deadlock. So, we must hold onto these binders until + // mNodeMutex is no longer taken. + auto temp = std::move(mNodeForAddress); + mNodeForAddress.clear(); // RpcState isn't reusable, but for future/explicit _l.unlock(); - tempHoldBinder.clear(); // explicit + temp.clear(); // explicit } void RpcState::dumpLocked() { ALOGE("DUMP OF RpcState %p", this); ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size()); for (const auto& [address, node] : mNodeForAddress) { - sp<IBinder> binder = node.binder.promote(); - - const char* desc; - if (binder) { - if (binder->remoteBinder()) { - if (binder->remoteBinder()->isRpcBinder()) { - desc = "(rpc binder proxy)"; - } else { - desc = "(binder proxy)"; - } + ALOGE("- address: %" PRIu64 " %s", address, node.toString().c_str()); + } + ALOGE("END DUMP OF RpcState"); +} + +std::string RpcState::BinderNode::toString() const { + sp<IBinder> strongBinder = this->binder.promote(); + + const char* desc; + if (strongBinder) { + if (strongBinder->remoteBinder()) { + if (strongBinder->remoteBinder()->isRpcBinder()) { + desc = "(rpc binder proxy)"; } else { - desc = "(local binder)"; + desc = "(binder proxy)"; } } else { - desc = "(null)"; + desc = "(local binder)"; } - - ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a: %" PRIu64 " type: %s", - node.binder.unsafe_get(), node.timesSent, node.timesRecd, address, desc); + } else { + desc = "(not promotable)"; } - ALOGE("END DUMP OF RpcState"); -} + return StringPrintf("node{%p times sent: %zu times recd: %zu type: %s}", + this->binder.unsafe_get(), this->timesSent, this->timesRecd, desc); +} RpcState::CommandData::CommandData(size_t size) : mSize(size) { // The maximum size for regular binder is 1MB for all concurrent @@ -581,13 +584,12 @@ status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connecti return waitForReply(connection, session, reply); } -static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsCount) { - (void)p; +static void cleanup_reply_data(const uint8_t* data, size_t dataSize, const binder_size_t* objects, + size_t objectsCount) { delete[] const_cast<uint8_t*>(data); (void)dataSize; LOG_ALWAYS_FATAL_IF(objects != nullptr); - LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount); + (void)objectsCount; } status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection, @@ -643,14 +645,21 @@ status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection, Span<const uint32_t> objectTableSpan; if (session->getProtocolVersion().value() >= RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) { - Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize); + std::optional<Span<const uint8_t>> objectTableBytes = + parcelSpan.splitOff(rpcReply.parcelDataSize); + if (!objectTableBytes.has_value()) { + ALOGE("Parcel size larger than available bytes: %" PRId32 " vs %zu. Terminating!", + rpcReply.parcelDataSize, parcelSpan.byteSize()); + (void)session->shutdownAndWait(false); + return BAD_VALUE; + } std::optional<Span<const uint32_t>> maybeSpan = - objectTableBytes.reinterpret<const uint32_t>(); + objectTableBytes->reinterpret<const uint32_t>(); if (!maybeSpan.has_value()) { ALOGE("Bad object table size inferred from RpcWireReply. Saw bodySize=%" PRId32 " sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!", command.bodySize, rpcReplyWireSize, rpcReply.parcelDataSize, - objectTableBytes.size); + objectTableBytes->size); return BAD_VALUE; } objectTableSpan = *maybeSpan; @@ -787,9 +796,8 @@ status_t RpcState::processTransact( std::move(ancillaryFds)); } -static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize, +static void do_nothing_to_transact_data(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount) { - (void)p; (void)data; (void)dataSize; (void)objects; @@ -893,15 +901,22 @@ processTransactInternalTailCall: Span<const uint32_t> objectTableSpan; if (session->getProtocolVersion().value() > RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) { - Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize); + std::optional<Span<const uint8_t>> objectTableBytes = + parcelSpan.splitOff(transaction->parcelDataSize); + if (!objectTableBytes.has_value()) { + ALOGE("Parcel size (%" PRId32 ") greater than available bytes (%zu). Terminating!", + transaction->parcelDataSize, parcelSpan.byteSize()); + (void)session->shutdownAndWait(false); + return BAD_VALUE; + } std::optional<Span<const uint32_t>> maybeSpan = - objectTableBytes.reinterpret<const uint32_t>(); + objectTableBytes->reinterpret<const uint32_t>(); if (!maybeSpan.has_value()) { ALOGE("Bad object table size inferred from RpcWireTransaction. Saw bodySize=%zu " "sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!", transactionData.size(), sizeof(RpcWireTransaction), - transaction->parcelDataSize, objectTableBytes.size); + transaction->parcelDataSize, objectTableBytes->size); return BAD_VALUE; } objectTableSpan = *maybeSpan; diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index 6fb2e4a011..892ecd691d 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -258,6 +258,8 @@ private: // // (no additional data specific to remote binders) + + std::string toString() const; }; // checks if there is any reference left to a node and erases it. If erase diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h index 7c6d6f17b1..e04199c75a 100644 --- a/libs/binder/Utils.h +++ b/libs/binder/Utils.h @@ -48,9 +48,11 @@ struct Span { // Truncates `this` to a length of `offset` and returns a span with the // remainder. // - // Aborts if offset > size. - Span<T> splitOff(size_t offset) { - LOG_ALWAYS_FATAL_IF(offset > size); + // `std::nullopt` iff offset > size. + std::optional<Span<T>> splitOff(size_t offset) { + if (offset > size) { + return std::nullopt; + } Span<T> rest = {data + offset, size - offset}; size = offset; return rest; diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 8ce3bc9dc9..c01e92f043 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -217,9 +217,8 @@ private: void clearCaller(); static void threadDestructor(void *st); - static void freeBuffer(Parcel* parcel, - const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsSize); + static void freeBuffer(const uint8_t* data, size_t dataSize, const binder_size_t* objects, + size_t objectsSize); static void logExtendedError(); const sp<ProcessState> mProcess; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 32b0ded55c..54692398c6 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -598,9 +598,9 @@ public: void print(TextOutput& to, uint32_t flags = 0) const; private: - typedef void (*release_func)(Parcel* parcel, - const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsSize); + // `objects` and `objectsSize` always 0 for RPC Parcels. + typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects, + size_t objectsSize); uintptr_t ipcData() const; size_t ipcDataSize() const; @@ -1184,10 +1184,20 @@ private: c->clear(); // must clear before resizing/reserving otherwise move ctors may be called. if constexpr (is_pointer_equivalent_array_v<T>) { // could consider POD without gaps and alignment of 4. - auto data = reinterpret_cast<const T*>( - readInplace(static_cast<size_t>(size) * sizeof(T))); + size_t dataLen; + if (__builtin_mul_overflow(size, sizeof(T), &dataLen)) { + return -EOVERFLOW; + } + auto data = reinterpret_cast<const T*>(readInplace(dataLen)); if (data == nullptr) return BAD_VALUE; - c->insert(c->begin(), data, data + size); // insert should do a reserve(). + // std::vector::insert and similar methods will require type-dependent + // byte alignment when inserting from a const iterator such as `data`, + // e.g. 8 byte alignment for int64_t, and so will not work if `data` + // is 4 byte aligned (which is all Parcel guarantees). Copying + // the contents into the vector directly, where possible, circumvents + // this. + c->resize(size); + memcpy(c->data(), data, dataLen); } else if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, char16_t>) { c->reserve(size); // avoids default initialization diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index 882dfbf0fa..9679a5f477 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -130,7 +130,7 @@ private: void* mVMStart; // Protects thread count and wait variables below. - pthread_mutex_t mThreadCountLock; + mutable pthread_mutex_t mThreadCountLock; // Broadcast whenever mWaitingForThreads > 0 pthread_cond_t mThreadCountDecrement; // Number of binder threads current executing a command. diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 9318c27cf0..52bda0e8ed 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -29,6 +29,7 @@ namespace android { class FdTrigger; +class RpcServerTrusty; class RpcSocketAddress; /** @@ -189,6 +190,7 @@ public: ~RpcServer(); private: + friend RpcServerTrusty; friend sp<RpcServer>; explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx); @@ -196,8 +198,10 @@ private: void onSessionIncomingThreadEnded() override; static constexpr size_t kRpcAddressSize = 128; - static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd, - std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen); + static void establishConnection( + sp<RpcServer>&& server, base::unique_fd clientFd, + std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen, + std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn); [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address); const std::unique_ptr<RpcTransportCtx> mCtx; diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index a2b28db4a3..9d94e005c3 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -31,6 +31,7 @@ namespace android { class Parcel; class RpcServer; +class RpcServerTrusty; class RpcSocketAddress; class RpcState; class RpcTransport; @@ -202,6 +203,7 @@ public: private: friend sp<RpcSession>; friend RpcServer; + friend RpcServerTrusty; friend RpcState; explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx); diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index f3f2886396..6bc9814048 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -89,12 +89,12 @@ LIBBINDER_NDK { # introduced=29 AStatus_getStatus; AStatus_isOk; AStatus_newOk; - ABinderProcess_joinThreadPool; # apex llndk - ABinderProcess_setThreadPoolMaxThreadCount; # apex llndk - ABinderProcess_startThreadPool; # apex llndk - AServiceManager_addService; # apex llndk - AServiceManager_checkService; # apex llndk - AServiceManager_getService; # apex llndk + ABinderProcess_joinThreadPool; # systemapi llndk + ABinderProcess_setThreadPoolMaxThreadCount; # systemapi llndk + ABinderProcess_startThreadPool; # systemapi llndk + AServiceManager_addService; # systemapi llndk + AServiceManager_checkService; # systemapi llndk + AServiceManager_getService; # systemapi llndk }; LIBBINDER_NDK30 { # introduced=30 @@ -105,30 +105,30 @@ LIBBINDER_NDK30 { # introduced=30 AStatus_deleteDescription; AParcel_fromJavaParcel; - AIBinder_markSystemStability; # apex + AIBinder_markSystemStability; # systemapi AIBinder_markVendorStability; # llndk - AIBinder_markVintfStability; # apex llndk - AIBinder_Class_setHandleShellCommand; # apex llndk + AIBinder_markVintfStability; # systemapi llndk + AIBinder_Class_setHandleShellCommand; # systemapi llndk }; LIBBINDER_NDK31 { # introduced=31 global: - ABinderProcess_handlePolledCommands; # apex - ABinderProcess_setupPolling; # apex - AIBinder_getCallingSid; # apex - AIBinder_setRequestingSid; # apex + ABinderProcess_handlePolledCommands; # systemapi + ABinderProcess_setupPolling; # systemapi + AIBinder_getCallingSid; # systemapi + AIBinder_setRequestingSid; # systemapi AParcel_markSensitive; # systemapi llndk - AServiceManager_forEachDeclaredInstance; # apex llndk - AServiceManager_forceLazyServicesPersist; # apex llndk - AServiceManager_isDeclared; # apex llndk - AServiceManager_isUpdatableViaApex; # apex + AServiceManager_forEachDeclaredInstance; # systemapi llndk + AServiceManager_forceLazyServicesPersist; # systemapi llndk + AServiceManager_isDeclared; # systemapi llndk + AServiceManager_isUpdatableViaApex; # systemapi AServiceManager_reRegister; # llndk - AServiceManager_registerLazyService; # apex llndk + AServiceManager_registerLazyService; # systemapi llndk AServiceManager_setActiveServicesCallback; # llndk AServiceManager_tryUnregister; # llndk - AServiceManager_waitForService; # apex llndk + AServiceManager_waitForService; # systemapi llndk - AIBinder_forceDowngradeToSystemStability; # apex + AIBinder_forceDowngradeToSystemStability; # systemapi AIBinder_forceDowngradeToVendorStability; # llndk AIBinder_Class_getDescriptor; @@ -146,8 +146,8 @@ LIBBINDER_NDK33 { # introduced=33 AIBinder_Class_disableInterfaceTokenHeader; AIBinder_DeathRecipient_setOnUnlinked; AIBinder_isHandlingTransaction; - AIBinder_setInheritRt; # apex llndk - AIBinder_setMinSchedulerPolicy; # apex llndk + AIBinder_setInheritRt; # systemapi llndk + AIBinder_setMinSchedulerPolicy; # systemapi llndk AParcel_marshal; AParcel_unmarshal; }; diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 4ed3309e0c..e72f39c24a 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -1310,7 +1310,7 @@ TEST_F(BinderLibTest, ThreadPoolAvailableThreads) { * not exceed 16 (15 Max + pool thread). */ std::vector<std::thread> ts; - for (size_t i = 0; i < kKernelThreads - 1; i++) { + for (size_t i = 0; i < kKernelThreads; i++) { ts.push_back(std::thread([&] { Parcel local_reply; EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply), @@ -1318,7 +1318,7 @@ TEST_F(BinderLibTest, ThreadPoolAvailableThreads) { })); } - data.writeInt32(1); + data.writeInt32(100); // Give a chance for all threads to be used EXPECT_THAT(server->transact(BINDER_LIB_TEST_UNLOCK_AFTER_MS, data, &reply), NO_ERROR); @@ -1329,8 +1329,7 @@ TEST_F(BinderLibTest, ThreadPoolAvailableThreads) { EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply), StatusEq(NO_ERROR)); replyi = reply.readInt32(); - // No more than 16 threads should exist. - EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1); + EXPECT_EQ(replyi, kKernelThreads + 1); } size_t epochMillis() { diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 4e41d8e604..8afb4031fb 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -930,7 +930,7 @@ TEST_P(BinderRpcThreads, OnewayCallQueueing) { size_t epochMsAfter = epochMillis(); - EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps); + EXPECT_GE(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps); saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface); } @@ -1029,13 +1029,6 @@ TEST_P(BinderRpc, Callbacks) { // since this session has an incoming connection w/ a threadpool, we // need to manually shut it down EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true)); - - proc.proc.host.setCustomExitStatusCheck([](int wstatus) { - // Flaky. Sometimes gets SIGABRT. - EXPECT_TRUE((WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) || - (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)) - << "server process failed: " << WaitStatusToString(wstatus); - }); proc.expectAlreadyShutdown = true; } } diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index 2ca6ebdbd2..0210237ed8 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -7,6 +7,22 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +aidl_interface { + name: "binderReadParcelIface", + host_supported: true, + unstable: true, + srcs: [ + "EmptyParcelable.aidl", + "SingleDataParcelable.aidl", + "GenericDataParcelable.aidl", + ], + backend: { + java: { + enabled: false, + }, + }, +} + cc_fuzz { name: "binder_parcel_fuzzer", host_supported: true, @@ -29,6 +45,8 @@ cc_fuzz { "libcutils", "libhidlbase", "liblog", + "binderReadParcelIface-cpp", + "binderReadParcelIface-ndk", ], target: { diff --git a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl new file mode 100644 index 0000000000..96d6223d3d --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +parcelable EmptyParcelable{ +}
\ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl new file mode 100644 index 0000000000..fc2542b36c --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +parcelable GenericDataParcelable { + int data; + float majorVersion; + float minorVersion; + IBinder binder; + ParcelFileDescriptor fileDescriptor; + int[] array; +}
\ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl new file mode 100644 index 0000000000..d62891b26a --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +parcelable SingleDataParcelable{ + int data; +}
\ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp index 7059d30bb4..9dac2c98a7 100644 --- a/libs/binder/tests/parcel_fuzzer/binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder.cpp @@ -16,6 +16,9 @@ #define FUZZ_LOG_TAG "binder" #include "binder.h" +#include "EmptyParcelable.h" +#include "GenericDataParcelable.h" +#include "SingleDataParcelable.h" #include "util.h" #include <android-base/hex.h> @@ -354,6 +357,24 @@ std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS { status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result); FUZZ_LOG() << " status: " << status << " result: " << result; }, + [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) { + FUZZ_LOG() << "about to call readFromParcel() with status for EmptyParcelable"; + EmptyParcelable emptyParcelable{}; + status_t status = emptyParcelable.readFromParcel(&p); + FUZZ_LOG() << " status: " << status; + }, + [] (const ::android::Parcel& p , FuzzedDataProvider& /*provider*/) { + FUZZ_LOG() << "about to call readFromParcel() with status for SingleDataParcelable"; + SingleDataParcelable singleDataParcelable; + status_t status = singleDataParcelable.readFromParcel(&p); + FUZZ_LOG() <<" status: " << status; + }, + [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) { + FUZZ_LOG() << "about to call readFromParcel() with status for GenericDataParcelable"; + GenericDataParcelable genericDataParcelable; + status_t status = genericDataParcelable.readFromParcel(&p); + FUZZ_LOG() <<" status: " << status; + }, }; // clang-format on #pragma clang diagnostic pop diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp index 26d67704b2..af773a02f7 100644 --- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp @@ -16,6 +16,9 @@ #define FUZZ_LOG_TAG "binder_ndk" #include "binder_ndk.h" +#include "aidl/EmptyParcelable.h" +#include "aidl/GenericDataParcelable.h" +#include "aidl/SingleDataParcelable.h" #include <android/binder_parcel_utils.h> #include <android/binder_parcelable_utils.h> @@ -177,5 +180,24 @@ std::vector<ParcelRead<NdkParcelAdapter>> BINDER_NDK_PARCEL_READ_FUNCTIONS{ PARCEL_READ(std::array<ndk::ScopedFileDescriptor COMMA 3>, ndk::AParcel_readData), PARCEL_READ(std::array<std::shared_ptr<ISomeInterface> COMMA 3>, ndk::AParcel_readData), #undef COMMA + + [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) { + FUZZ_LOG() << "about to read parcel using readFromParcel for EmptyParcelable"; + aidl::EmptyParcelable emptyParcelable; + binder_status_t status = emptyParcelable.readFromParcel(p.aParcel()); + FUZZ_LOG() << "status: " << status; + }, + [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) { + FUZZ_LOG() << "about to read parcel using readFromParcel for SingleDataParcelable"; + aidl::SingleDataParcelable singleDataParcelable; + binder_status_t status = singleDataParcelable.readFromParcel(p.aParcel()); + FUZZ_LOG() << "status: " << status; + }, + [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) { + FUZZ_LOG() << "about to read parcel using readFromParcel for GenericDataParcelable"; + aidl::GenericDataParcelable genericDataParcelable; + binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel()); + FUZZ_LOG() << "status: " << status; + }, }; // clang-format on diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h index 843b6e3011..6ea970825b 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h @@ -19,10 +19,14 @@ #include <android-base/unique_fd.h> #include <fuzzer/FuzzedDataProvider.h> +#include <vector> + namespace android { // always valid or aborts // get a random FD for use in fuzzing, of a few different specific types -base::unique_fd getRandomFd(FuzzedDataProvider* provider); +// +// may return multiple FDs (e.g. pipe), but will always return at least one +std::vector<base::unique_fd> getRandomFds(FuzzedDataProvider* provider); } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h index 459fb127c2..27587a9162 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h @@ -33,10 +33,13 @@ struct RandomParcelOptions { /** * Fill parcel data, including some random binder objects and FDs * + * May insert additional FDs/binders if they own data related to the Parcel (e.g. the other + * end of a pipe). + * * p - the Parcel to fill * provider - takes ownership and completely consumes provider * writeHeader - optional function to write a specific header once the format of the parcel is * picked (for instance, to write an interface header) */ -void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {}); +void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options); } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index d5aa353af0..32494e3f77 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -44,7 +44,7 @@ void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) { std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>( provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes())); - fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options); + fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options); Parcel reply; (void)target->transact(code, data, &reply, flags); diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp index 180a177689..bef4ab6e99 100644 --- a/libs/binder/tests/parcel_fuzzer/main.cpp +++ b/libs/binder/tests/parcel_fuzzer/main.cpp @@ -35,17 +35,22 @@ #include <sys/time.h> using android::fillRandomParcel; +using android::RandomParcelOptions; using android::sp; using android::base::HexString; -void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) { +void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider, + RandomParcelOptions* options) { // TODO: functionality to create random parcels for libhwbinder parcels + (void)options; + std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>(); p->setData(input.data(), input.size()); } -static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) { +static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider, + RandomParcelOptions* options) { // fill underlying parcel using functions to fill random libbinder parcel - fillRandomParcel(p->parcel(), std::move(provider)); + fillRandomParcel(p->parcel(), std::move(provider), options); } template <typename P, typename B> @@ -55,9 +60,11 @@ void doTransactFuzz(const char* backend, const sp<B>& binder, FuzzedDataProvider FUZZ_LOG() << "backend: " << backend; + RandomParcelOptions options; + P reply; P data; - fillRandomParcel(&data, std::move(provider)); + fillRandomParcel(&data, std::move(provider), &options); (void)binder->transact(code, data, &reply, flag); } @@ -73,8 +80,10 @@ void doReadFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads, std::vector<uint8_t> instructions = provider.ConsumeBytes<uint8_t>( provider.ConsumeIntegralInRange<size_t>(0, maxInstructions)); + RandomParcelOptions options; + P p; - fillRandomParcel(&p, std::move(provider)); + fillRandomParcel(&p, std::move(provider), &options); // since we are only using a byte to index CHECK(reads.size() <= 255) << reads.size(); @@ -103,9 +112,12 @@ void doAppendFuzz(const char* backend, FuzzedDataProvider&& provider) { std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>( provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes())); + // same options so that FDs and binders could be shared in both Parcels + RandomParcelOptions options; + P p0, p1; - fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size())); - fillRandomParcel(&p1, std::move(provider)); + fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()), &options); + fillRandomParcel(&p1, std::move(provider), &options); FUZZ_LOG() << "backend: " << backend; FUZZ_LOG() << "start: " << start << " len: " << len; diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp index ab0b7e306f..3fcf104e81 100644 --- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp @@ -23,13 +23,44 @@ namespace android { -base::unique_fd getRandomFd(FuzzedDataProvider* provider) { - int fd = provider->PickValueInArray<std::function<int()>>({ - []() { return ashmem_create_region("binder test region", 1024); }, - []() { return open("/dev/null", O_RDWR); }, +using base::unique_fd; + +std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) { + std::vector<unique_fd> fds = provider->PickValueInArray< + std::function<std::vector<unique_fd>()>>({ + [&]() { + std::vector<unique_fd> ret; + ret.push_back(unique_fd( + ashmem_create_region("binder test region", + provider->ConsumeIntegralInRange<size_t>(0, 4096)))); + return ret; + }, + [&]() { + std::vector<unique_fd> ret; + ret.push_back(unique_fd(open("/dev/null", O_RDWR))); + return ret; + }, + [&]() { + int pipefds[2]; + + int flags = O_CLOEXEC; + if (provider->ConsumeBool()) flags |= O_DIRECT; + if (provider->ConsumeBool()) flags |= O_NONBLOCK; + + CHECK_EQ(0, pipe2(pipefds, flags)); + + if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]); + + std::vector<unique_fd> ret; + ret.push_back(unique_fd(pipefds[0])); + ret.push_back(unique_fd(pipefds[1])); + return ret; + }, })(); - CHECK(fd >= 0); - return base::unique_fd(fd); + + for (const auto& fd : fds) CHECK(fd.ok()) << fd.get(); + + return fds; } } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index 0204f5ed61..51cb768d3d 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -39,23 +39,24 @@ static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) { CHECK(OK == p->write(data.data(), data.size())); } -void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, - const RandomParcelOptions& options) { +void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) { + CHECK_NE(options, nullptr); + if (provider.ConsumeBool()) { auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make()); CHECK_EQ(OK, session->addNullDebuggingClient()); p->markForRpc(session); - if (options.writeHeader) { - options.writeHeader(p, provider); + if (options->writeHeader) { + options->writeHeader(p, provider); } fillRandomParcelData(p, std::move(provider)); return; } - if (options.writeHeader) { - options.writeHeader(p, provider); + if (options->writeHeader) { + options->writeHeader(p, provider); } while (provider.remaining_bytes() > 0) { @@ -69,15 +70,21 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, }, // write FD [&]() { - if (options.extraFds.size() > 0 && provider.ConsumeBool()) { - const base::unique_fd& fd = options.extraFds.at( + if (options->extraFds.size() > 0 && provider.ConsumeBool()) { + const base::unique_fd& fd = options->extraFds.at( provider.ConsumeIntegralInRange<size_t>(0, - options.extraFds.size() - + options->extraFds.size() - 1)); CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/)); } else { - base::unique_fd fd = getRandomFd(&provider); - CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/)); + std::vector<base::unique_fd> fds = getRandomFds(&provider); + 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())); } }, // write binder @@ -98,10 +105,10 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, return IInterface::asBinder(defaultServiceManager()); }, [&]() -> sp<IBinder> { - if (options.extraBinders.size() > 0 && provider.ConsumeBool()) { - return options.extraBinders.at( + if (options->extraBinders.size() > 0 && provider.ConsumeBool()) { + return options->extraBinders.at( provider.ConsumeIntegralInRange< - size_t>(0, options.extraBinders.size() - 1)); + size_t>(0, options->extraBinders.size() - 1)); } else { return nullptr; } diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp new file mode 100644 index 0000000000..187add4a7b --- /dev/null +++ b/libs/binder/trusty/OS.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <openssl/rand.h> + +#include "../OS.h" + +using android::base::Result; + +namespace android { + +Result<void> setNonBlocking(android::base::borrowed_fd fd) { + // Trusty IPC syscalls are all non-blocking by default. + return {}; +} + +status_t getRandomBytes(uint8_t* data, size_t size) { + int res = RAND_bytes(data, size); + return res == 1 ? OK : UNKNOWN_ERROR; +} + +} // namespace android diff --git a/libs/binder/trusty/README.md b/libs/binder/trusty/README.md new file mode 100644 index 0000000000..1a273aab10 --- /dev/null +++ b/libs/binder/trusty/README.md @@ -0,0 +1,39 @@ +# Binder for Trusty + +This is the Trusty port of the libbinder library. +To build it, take the following steps: + +* Check out copies of the Trusty and AOSP repositories. +* Apply the patches from the `trusty_binder` topic on both repositories. +* Build Trusty normally using `build.py`. +* Run the sample AIDL test for Trusty: + ```shell + $ ./build-root/.../run --headless --boot-test com.android.trusty.aidl.test + ``` + +To run the Android-Trusty IPC test, do the following: + +* Build AOSP for the `qemu_trusty_arm64-userdebug` target: + ```shell + $ lunch qemu_trusty_arm64-userdebug + $ m + ``` +* In the Trusty directory, run the emulator with the newly built Android: + ```shell + $ ./build-root/.../run --android /path/to/aosp + ``` +* Using either `adb` or the shell inside the emulator itself, run the Trusty + Binder test as root: + ```shell + # /data/nativetest64/vendor/trusty_binder_test/trusty_binder_test + ``` + +## Running the AIDL compiler +For now, you will need to run the AIDL compiler manually to generate the C++ +source code for Trusty clients and services. The general syntax is: +```shell +$ aidl --lang=cpp -o <output directory> -h <output header directory> <AIDL files...> +``` + +The compiler will emit some `.cpp` files in the output directory and their +corresponding `.h` files in the header directory. diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp new file mode 100644 index 0000000000..e8b91e7a4c --- /dev/null +++ b/libs/binder/trusty/RpcServerTrusty.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "RpcServerTrusty" + +#include <binder/Parcel.h> +#include <binder/RpcServer.h> +#include <binder/RpcServerTrusty.h> +#include <binder/RpcThreads.h> +#include <binder/RpcTransportTipcTrusty.h> +#include <log/log.h> + +#include "../FdTrigger.h" +#include "../RpcState.h" +#include "TrustyStatus.h" + +using android::base::unexpected; + +namespace android { + +android::base::expected<sp<RpcServerTrusty>, int> RpcServerTrusty::make( + tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl, + size_t msgMaxSize, std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) { + // Default is without TLS. + if (rpcTransportCtxFactory == nullptr) + rpcTransportCtxFactory = RpcTransportCtxFactoryTipcTrusty::make(); + auto ctx = rpcTransportCtxFactory->newServerCtx(); + if (ctx == nullptr) { + return unexpected(ERR_NO_MEMORY); + } + + auto srv = sp<RpcServerTrusty>::make(std::move(ctx), std::move(portName), std::move(portAcl), + msgMaxSize); + if (srv == nullptr) { + return unexpected(ERR_NO_MEMORY); + } + + int rc = tipc_add_service(handleSet, &srv->mTipcPort, 1, 0, &kTipcOps); + if (rc != NO_ERROR) { + return unexpected(rc); + } + return srv; +} + +RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName, + std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize) + : mRpcServer(sp<RpcServer>::make(std::move(ctx))), + mPortName(std::move(portName)), + mPortAcl(std::move(portAcl)) { + mTipcPort.name = mPortName.c_str(); + mTipcPort.msg_max_size = msgMaxSize; + mTipcPort.msg_queue_len = 6; // Three each way + mTipcPort.priv = this; + + if (mPortAcl) { + // Initialize the array of pointers to uuids. + // The pointers in mUuidPtrs should stay valid across moves of + // RpcServerTrusty (the addresses of a std::vector's elements + // shouldn't change when the vector is moved), but would be invalidated + // by a copy which is why we disable the copy constructor and assignment + // operator for RpcServerTrusty. + auto numUuids = mPortAcl->uuids.size(); + mUuidPtrs.resize(numUuids); + for (size_t i = 0; i < numUuids; i++) { + mUuidPtrs[i] = &mPortAcl->uuids[i]; + } + + // Copy the contents of portAcl into the tipc_port_acl structure that we + // pass to tipc_add_service + mTipcPortAcl.flags = mPortAcl->flags; + mTipcPortAcl.uuid_num = numUuids; + mTipcPortAcl.uuids = mUuidPtrs.data(); + mTipcPortAcl.extra_data = mPortAcl->extraData; + + mTipcPort.acl = &mTipcPortAcl; + } else { + mTipcPort.acl = nullptr; + } +} + +int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, + void** ctx_p) { + auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv)); + server->mRpcServer->mShutdownTrigger = FdTrigger::make(); + server->mRpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread(); + + int rc = NO_ERROR; + auto joinFn = [&](sp<RpcSession>&& session, RpcSession::PreJoinSetupResult&& result) { + if (result.status != OK) { + rc = statusToTrusty(result.status); + return; + } + + /* Save the session for easy access */ + *ctx_p = session.get(); + }; + + base::unique_fd clientFd(chan); + std::array<uint8_t, RpcServer::kRpcAddressSize> addr; + constexpr size_t addrLen = sizeof(*peer); + memcpy(addr.data(), peer, addrLen); + RpcServer::establishConnection(sp(server->mRpcServer), std::move(clientFd), addr, addrLen, + joinFn); + + return rc; +} + +int RpcServerTrusty::handleMessage(const tipc_port* port, handle_t chan, void* ctx) { + auto* session = reinterpret_cast<RpcSession*>(ctx); + status_t status = session->state()->drainCommands(session->mConnections.mIncoming[0], session, + RpcState::CommandType::ANY); + if (status != OK) { + LOG_RPC_DETAIL("Binder connection thread closing w/ status %s", + statusToString(status).c_str()); + } + + return NO_ERROR; +} + +void RpcServerTrusty::handleDisconnect(const tipc_port* port, handle_t chan, void* ctx) {} + +void RpcServerTrusty::handleChannelCleanup(void* ctx) { + auto* session = reinterpret_cast<RpcSession*>(ctx); + auto& connection = session->mConnections.mIncoming.at(0); + LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection), + "bad state: connection object guaranteed to be in list"); +} + +} // namespace android diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp new file mode 100644 index 0000000000..e0d80fbe7b --- /dev/null +++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "RpcTransportTipcTrusty" + +#include <trusty_ipc.h> + +#include <binder/RpcSession.h> +#include <binder/RpcTransportTipcTrusty.h> +#include <log/log.h> + +#include "../FdTrigger.h" +#include "../RpcState.h" +#include "TrustyStatus.h" + +namespace android { + +namespace { + +// RpcTransport for Trusty. +class RpcTransportTipcTrusty : public RpcTransport { +public: + explicit RpcTransportTipcTrusty(android::base::unique_fd socket) : mSocket(std::move(socket)) {} + ~RpcTransportTipcTrusty() { releaseMessage(); } + + status_t pollRead() override { + auto status = ensureMessage(false); + if (status != OK) { + return status; + } + return mHaveMessage ? OK : WOULD_BLOCK; + } + + status_t interruptableWriteFully( + FdTrigger* fdTrigger, iovec* iovs, int niovs, + const std::optional<android::base::function_ref<status_t()>>& altPoll, + const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) + override { + if (niovs < 0) { + return BAD_VALUE; + } + + size_t size = 0; + for (int i = 0; i < niovs; i++) { + size += iovs[i].iov_len; + } + + ipc_msg_t msg{ + .num_iov = static_cast<uint32_t>(niovs), + .iov = iovs, + .num_handles = 0, // TODO: add ancillaryFds + .handles = nullptr, + }; + int rc = send_msg(mSocket.get(), &msg); + if (rc == ERR_NOT_ENOUGH_BUFFER) { + // Peer is blocked, wait until it unblocks. + // TODO: when tipc supports a send-unblocked handler, + // save the message here in a queue and retry it asynchronously + // when the handler gets called by the library + uevent uevt; + do { + rc = ::wait(mSocket.get(), &uevt, INFINITE_TIME); + if (rc < 0) { + return statusFromTrusty(rc); + } + if (uevt.event & IPC_HANDLE_POLL_HUP) { + return DEAD_OBJECT; + } + } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED)); + + // Retry the send, it should go through this time because + // sending is now unblocked + rc = send_msg(mSocket.get(), &msg); + } + if (rc < 0) { + return statusFromTrusty(rc); + } + LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size, + "Sent the wrong number of bytes %d!=%zu", rc, size); + + return OK; + } + + status_t interruptableReadFully( + FdTrigger* fdTrigger, iovec* iovs, int niovs, + const std::optional<android::base::function_ref<status_t()>>& altPoll, + std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override { + if (niovs < 0) { + return BAD_VALUE; + } + + // If iovs has one or more empty vectors at the end and + // we somehow advance past all the preceding vectors and + // pass some or all of the empty ones to sendmsg/recvmsg, + // the call will return processSize == 0. In that case + // we should be returning OK but instead return DEAD_OBJECT. + // To avoid this problem, we make sure here that the last + // vector at iovs[niovs - 1] has a non-zero length. + while (niovs > 0 && iovs[niovs - 1].iov_len == 0) { + niovs--; + } + if (niovs == 0) { + // The vectors are all empty, so we have nothing to read. + return OK; + } + + while (true) { + auto status = ensureMessage(true); + if (status != OK) { + return status; + } + + ipc_msg_t msg{ + .num_iov = static_cast<uint32_t>(niovs), + .iov = iovs, + .num_handles = 0, // TODO: support ancillaryFds + .handles = nullptr, + }; + int rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg); + if (rc < 0) { + return statusFromTrusty(rc); + } + + size_t processSize = static_cast<size_t>(rc); + mMessageOffset += processSize; + LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len, + "Message offset exceeds length %zu/%zu", mMessageOffset, + mMessageInfo.len); + + // Release the message if all of it has been read + if (mMessageOffset == mMessageInfo.len) { + releaseMessage(); + } + + while (processSize > 0 && niovs > 0) { + auto& iov = iovs[0]; + if (processSize < iov.iov_len) { + // Advance the base of the current iovec + iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize; + iov.iov_len -= processSize; + break; + } + + // The current iovec was fully written + processSize -= iov.iov_len; + iovs++; + niovs--; + } + if (niovs == 0) { + LOG_ALWAYS_FATAL_IF(processSize > 0, + "Reached the end of iovecs " + "with %zd bytes remaining", + processSize); + return OK; + } + } + } + +private: + status_t ensureMessage(bool wait) { + int rc; + if (mHaveMessage) { + LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message"); + return OK; + } + + /* TODO: interruptible wait, maybe with a timeout??? */ + uevent uevt; + rc = ::wait(mSocket.get(), &uevt, wait ? INFINITE_TIME : 0); + if (rc < 0) { + if (rc == ERR_TIMED_OUT && !wait) { + // If we timed out with wait==false, then there's no message + return OK; + } + return statusFromTrusty(rc); + } + if (!(uevt.event & IPC_HANDLE_POLL_MSG)) { + /* No message, terminate here and leave mHaveMessage false */ + return OK; + } + + rc = get_msg(mSocket.get(), &mMessageInfo); + if (rc < 0) { + return statusFromTrusty(rc); + } + + mHaveMessage = true; + mMessageOffset = 0; + return OK; + } + + void releaseMessage() { + if (mHaveMessage) { + put_msg(mSocket.get(), mMessageInfo.id); + mHaveMessage = false; + } + } + + base::unique_fd mSocket; + + bool mHaveMessage = false; + ipc_msg_info mMessageInfo; + size_t mMessageOffset; +}; + +// RpcTransportCtx for Trusty. +class RpcTransportCtxTipcTrusty : public RpcTransportCtx { +public: + std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, + FdTrigger*) const override { + return std::make_unique<RpcTransportTipcTrusty>(std::move(fd)); + } + std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; } +}; + +} // namespace + +std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const { + return std::make_unique<RpcTransportCtxTipcTrusty>(); +} + +std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const { + return std::make_unique<RpcTransportCtxTipcTrusty>(); +} + +const char* RpcTransportCtxFactoryTipcTrusty::toCString() const { + return "trusty"; +} + +std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() { + return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>( + new RpcTransportCtxFactoryTipcTrusty()); +} + +} // namespace android diff --git a/libs/binder/trusty/TrustyStatus.cpp b/libs/binder/trusty/TrustyStatus.cpp new file mode 100644 index 0000000000..b1caf612bc --- /dev/null +++ b/libs/binder/trusty/TrustyStatus.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TrustyStatus.h" +#include "../RpcState.h" + +namespace android { + +status_t statusFromTrusty(int rc) { + LOG_RPC_DETAIL("Trusty error: %d", rc); + switch (rc) { + case NO_ERROR: + return OK; + case ERR_NOT_FOUND: + return NAME_NOT_FOUND; + case ERR_NOT_READY: + // We get this error if we try to perform an IPC operation when the + // channel is not ready + return INVALID_OPERATION; + case ERR_NO_MSG: + return WOULD_BLOCK; + case ERR_NO_MEMORY: + return NO_MEMORY; + case ERR_INVALID_ARGS: + return BAD_VALUE; + case ERR_NOT_ENOUGH_BUFFER: + return WOULD_BLOCK; + case ERR_TIMED_OUT: + return TIMED_OUT; + case ERR_ALREADY_EXISTS: + return ALREADY_EXISTS; + case ERR_CHANNEL_CLOSED: + return DEAD_OBJECT; + case ERR_NOT_ALLOWED: + return INVALID_OPERATION; + case ERR_NOT_SUPPORTED: + return INVALID_OPERATION; + case ERR_TOO_BIG: + return BAD_INDEX; + case ERR_CMD_UNKNOWN: + return UNKNOWN_TRANSACTION; + case ERR_BAD_STATE: + return INVALID_OPERATION; + case ERR_BAD_LEN: + return NOT_ENOUGH_DATA; + case ERR_BAD_HANDLE: + return BAD_VALUE; + case ERR_ACCESS_DENIED: + return PERMISSION_DENIED; + default: + return UNKNOWN_ERROR; + } +} + +int statusToTrusty(status_t status) { + switch (status) { + case OK: + return NO_ERROR; + case NO_MEMORY: + return ERR_NO_MEMORY; + case INVALID_OPERATION: + case BAD_VALUE: + case BAD_TYPE: + return ERR_NOT_VALID; + case NAME_NOT_FOUND: + return ERR_NOT_FOUND; + case PERMISSION_DENIED: + return ERR_ACCESS_DENIED; + case NO_INIT: + return ERR_NOT_CONFIGURED; + case ALREADY_EXISTS: + return ERR_ALREADY_EXISTS; + case DEAD_OBJECT: + return ERR_CHANNEL_CLOSED; + case BAD_INDEX: + return ERR_TOO_BIG; + case NOT_ENOUGH_DATA: + return ERR_BAD_LEN; + case WOULD_BLOCK: + return ERR_NO_MSG; + case TIMED_OUT: + return ERR_TIMED_OUT; + case UNKNOWN_TRANSACTION: + return ERR_CMD_UNKNOWN; + case FDS_NOT_ALLOWED: + return ERR_NOT_SUPPORTED; + case UNEXPECTED_NULL: + return ERR_NOT_VALID; + default: + return ERR_GENERIC; + } +} + +} // namespace android diff --git a/libs/binder/trusty/TrustyStatus.h b/libs/binder/trusty/TrustyStatus.h new file mode 100644 index 0000000000..fcb43f8451 --- /dev/null +++ b/libs/binder/trusty/TrustyStatus.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include <uapi/err.h> +#include <utils/Errors.h> + +namespace android { + +status_t statusFromTrusty(int rc); +int statusToTrusty(status_t status); + +} // namespace android diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h new file mode 100644 index 0000000000..e8fc9f988d --- /dev/null +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android-base/expected.h> +#include <android-base/macros.h> +#include <android-base/unique_fd.h> +#include <binder/IBinder.h> +#include <binder/RpcServer.h> +#include <binder/RpcSession.h> +#include <binder/RpcTransport.h> +#include <utils/Errors.h> +#include <utils/RefBase.h> + +#include <map> +#include <vector> + +#include <lib/tipc/tipc_srv.h> + +namespace android { + +/** + * This is the Trusty-specific RPC server code. + */ +class RpcServerTrusty final : public virtual RefBase { +public: + // C++ equivalent to tipc_port_acl that uses safe data structures instead of + // raw pointers, except for |extraData| which doesn't have a good + // equivalent. + struct PortAcl { + uint32_t flags; + std::vector<const uuid> uuids; + const void* extraData; + }; + + /** + * Creates an RPC server listening on the given port and adds it to the + * Trusty handle set at |handleSet|. + * + * The caller is responsible for calling tipc_run_event_loop() to start + * the TIPC event loop after creating one or more services here. + */ + static android::base::expected<sp<RpcServerTrusty>, int> make( + tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl, + size_t msgMaxSize, + std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr); + + void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); } + void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); } + void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); } + void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) { + mRpcServer->setPerSessionRootObject(std::move(object)); + } + sp<IBinder> getRootObject() { return mRpcServer->getRootObject(); } + +private: + // Both this class and RpcServer have multiple non-copyable fields, + // including mPortAcl below which can't be copied because mUuidPtrs + // holds pointers into it + DISALLOW_COPY_AND_ASSIGN(RpcServerTrusty); + + friend sp<RpcServerTrusty>; + explicit RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName, + std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize); + + static int handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, void** ctx_p); + static int handleMessage(const tipc_port* port, handle_t chan, void* ctx); + static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx); + static void handleChannelCleanup(void* ctx); + + static constexpr tipc_srv_ops kTipcOps = { + .on_connect = &handleConnect, + .on_message = &handleMessage, + .on_disconnect = &handleDisconnect, + .on_channel_cleanup = &handleChannelCleanup, + }; + + sp<RpcServer> mRpcServer; + std::string mPortName; + std::shared_ptr<const PortAcl> mPortAcl; + std::vector<const uuid*> mUuidPtrs; + tipc_port_acl mTipcPortAcl; + tipc_port mTipcPort; +}; + +} // namespace android diff --git a/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h new file mode 100644 index 0000000000..8eae8c2ec1 --- /dev/null +++ b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Wraps the transport layer of RPC. Implementation uses plain sockets. +// Note: don't use directly. You probably want newServerRpcTransportCtx / newClientRpcTransportCtx. + +#pragma once + +#include <memory> + +#include <binder/RpcTransport.h> + +namespace android { + +// RpcTransportCtxFactory with TLS disabled. +class RpcTransportCtxFactoryTipcTrusty : public RpcTransportCtxFactory { +public: + static std::unique_ptr<RpcTransportCtxFactory> make(); + + std::unique_ptr<RpcTransportCtx> newServerCtx() const override; + std::unique_ptr<RpcTransportCtx> newClientCtx() const override; + const char* toCString() const override; + +private: + RpcTransportCtxFactoryTipcTrusty() = default; +}; + +} // namespace android diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h new file mode 100644 index 0000000000..bf877a3179 --- /dev/null +++ b/libs/binder/trusty/include/log/log.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#define BINDER_LOG_LEVEL_NONE 0 +#define BINDER_LOG_LEVEL_NORMAL 1 +#define BINDER_LOG_LEVEL_VERBOSE 2 + +#ifndef BINDER_LOG_LEVEL +#define BINDER_LOG_LEVEL BINDER_LOG_LEVEL_NORMAL +#endif // BINDER_LOG_LEVEL + +#ifndef TLOG_TAG +#ifdef LOG_TAG +#define TLOG_TAG "libbinder-" LOG_TAG +#else // LOG_TAG +#define TLOG_TAG "libbinder" +#endif // LOG_TAG +#endif // TLOG_TAG + +#include <stdlib.h> +#include <trusty_log.h> + +static inline void __ignore_va_args__(...) {} + +#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL +#define ALOGD(fmt, ...) TLOGD(fmt "\n", ##__VA_ARGS__) +#define ALOGI(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__) +#define ALOGW(fmt, ...) TLOGW(fmt "\n", ##__VA_ARGS__) +#define ALOGE(fmt, ...) TLOGE(fmt "\n", ##__VA_ARGS__) +#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL +#define ALOGD(fmt, ...) \ + while (0) { \ + __ignore_va_args__(__VA_ARGS__); \ + } +#define ALOGI(fmt, ...) \ + while (0) { \ + __ignore_va_args__(__VA_ARGS__); \ + } +#define ALOGW(fmt, ...) \ + while (0) { \ + __ignore_va_args__(__VA_ARGS__); \ + } +#define ALOGE(fmt, ...) \ + while (0) { \ + __ignore_va_args__(__VA_ARGS__); \ + } +#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL + +#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE +#define IF_ALOGV() if (TLOG_LVL >= TLOG_LVL_INFO) +#define ALOGV(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__) +#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE +#define IF_ALOGV() if (false) +#define ALOGV(fmt, ...) \ + while (0) { \ + __ignore_va_args__(__VA_ARGS__); \ + } +#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE + +#define ALOGI_IF(cond, ...) \ + do { \ + if (cond) { \ + ALOGI(#cond ": " __VA_ARGS__); \ + } \ + } while (0) +#define ALOGE_IF(cond, ...) \ + do { \ + if (cond) { \ + ALOGE(#cond ": " __VA_ARGS__); \ + } \ + } while (0) +#define ALOGW_IF(cond, ...) \ + do { \ + if (cond) { \ + ALOGW(#cond ": " __VA_ARGS__); \ + } \ + } while (0) + +#define LOG_ALWAYS_FATAL(fmt, ...) \ + do { \ + TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \ + abort(); \ + } while (0) +#define LOG_ALWAYS_FATAL_IF(cond, ...) \ + do { \ + if (cond) { \ + LOG_ALWAYS_FATAL(#cond ": " __VA_ARGS__); \ + } \ + } while (0) +#define LOG_FATAL(fmt, ...) \ + do { \ + TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \ + abort(); \ + } while (0) +#define LOG_FATAL_IF(cond, ...) \ + do { \ + if (cond) { \ + LOG_FATAL(#cond ": " __VA_ARGS__); \ + } \ + } while (0) + +#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__) + +#define android_errorWriteLog(tag, subTag) \ + do { \ + TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \ + } while (0) diff --git a/libs/binder/trusty/logging.cpp b/libs/binder/trusty/logging.cpp new file mode 100644 index 0000000000..fd54744fdf --- /dev/null +++ b/libs/binder/trusty/logging.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define TLOG_TAG "libbinder" + +#include "android-base/logging.h" + +#include <trusty_log.h> +#include <iostream> +#include <string> + +#include <android-base/macros.h> +#include <android-base/strings.h> + +namespace android { +namespace base { + +static const char* GetFileBasename(const char* file) { + const char* last_slash = strrchr(file, '/'); + if (last_slash != nullptr) { + return last_slash + 1; + } + return file; +} + +// This splits the message up line by line, by calling log_function with a pointer to the start of +// each line and the size up to the newline character. It sends size = -1 for the final line. +template <typename F, typename... Args> +static void SplitByLines(const char* msg, const F& log_function, Args&&... args) { + const char* newline; + while ((newline = strchr(msg, '\n')) != nullptr) { + log_function(msg, newline - msg, args...); + msg = newline + 1; + } + + log_function(msg, -1, args...); +} + +void DefaultAborter(const char* abort_message) { + TLOGC("aborting: %s\n", abort_message); + abort(); +} + +static void TrustyLogLine(const char* msg, int length, android::base::LogSeverity severity, + const char* tag) { + switch (severity) { + case VERBOSE: + case DEBUG: + TLOGD("%s: %s\n", tag, msg); + break; + case INFO: + TLOGI("%s: %s\n", tag, msg); + break; + case WARNING: + TLOGW("%s: %s\n", tag, msg); + break; + case ERROR: + TLOGE("%s: %s\n", tag, msg); + break; + case FATAL_WITHOUT_ABORT: + case FATAL: + TLOGC("%s: %s\n", tag, msg); + break; + } +} + +void TrustyLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag, + const char*, unsigned int, const char* full_message) { + SplitByLines(full_message, TrustyLogLine, severity, tag); +} + +// This indirection greatly reduces the stack impact of having lots of +// checks/logging in a function. +class LogMessageData { +public: + LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag, + int error) + : file_(GetFileBasename(file)), + line_number_(line), + severity_(severity), + tag_(tag), + error_(error) {} + + const char* GetFile() const { return file_; } + + unsigned int GetLineNumber() const { return line_number_; } + + LogSeverity GetSeverity() const { return severity_; } + + const char* GetTag() const { return tag_; } + + int GetError() const { return error_; } + + std::ostream& GetBuffer() { return buffer_; } + + std::string ToString() const { return buffer_.str(); } + +private: + std::ostringstream buffer_; + const char* const file_; + const unsigned int line_number_; + const LogSeverity severity_; + const char* const tag_; + const int error_; + + DISALLOW_COPY_AND_ASSIGN(LogMessageData); +}; + +LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, + const char* tag, int error) + : LogMessage(file, line, severity, tag, error) {} + +LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, + int error) + : data_(new LogMessageData(file, line, severity, tag, error)) {} + +LogMessage::~LogMessage() { + // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM. + if (!WOULD_LOG(data_->GetSeverity())) { + return; + } + + // Finish constructing the message. + if (data_->GetError() != -1) { + data_->GetBuffer() << ": " << strerror(data_->GetError()); + } + std::string msg(data_->ToString()); + + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(), + msg.c_str()); + + // Abort if necessary. + if (data_->GetSeverity() == FATAL) { + DefaultAborter(msg.c_str()); + } +} + +std::ostream& LogMessage::stream() { + return data_->GetBuffer(); +} + +void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag, + const char* message) { + TrustyLogger(DEFAULT, severity, tag ?: "<unknown>", file, line, message); +} + +bool ShouldLog(LogSeverity severity, const char* tag) { + // This is controlled by Trusty's log level. + return true; +} + +} // namespace base +} // namespace android diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk new file mode 100644 index 0000000000..cd81a09316 --- /dev/null +++ b/libs/binder/trusty/rules.mk @@ -0,0 +1,82 @@ +# Copyright (C) 2021 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +LIBBINDER_DIR := frameworks/native/libs/binder +LIBBASE_DIR := system/libbase +LIBCUTILS_DIR := system/core/libcutils +LIBUTILS_DIR := system/core/libutils +FMTLIB_DIR := external/fmtlib + +MODULE_SRCS := \ + $(LOCAL_DIR)/logging.cpp \ + $(LOCAL_DIR)/OS.cpp \ + $(LOCAL_DIR)/RpcServerTrusty.cpp \ + $(LOCAL_DIR)/RpcTransportTipcTrusty.cpp \ + $(LOCAL_DIR)/TrustyStatus.cpp \ + $(LOCAL_DIR)/socket.cpp \ + $(LIBBINDER_DIR)/Binder.cpp \ + $(LIBBINDER_DIR)/BpBinder.cpp \ + $(LIBBINDER_DIR)/FdTrigger.cpp \ + $(LIBBINDER_DIR)/IInterface.cpp \ + $(LIBBINDER_DIR)/IResultReceiver.cpp \ + $(LIBBINDER_DIR)/Parcel.cpp \ + $(LIBBINDER_DIR)/RpcServer.cpp \ + $(LIBBINDER_DIR)/RpcSession.cpp \ + $(LIBBINDER_DIR)/RpcState.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)/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 \ + $(LIBBINDER_DIR)/include \ + $(LIBBASE_DIR)/include \ + $(LIBCUTILS_DIR)/include \ + $(LIBUTILS_DIR)/include \ + $(FMTLIB_DIR)/include \ + +MODULE_EXPORT_COMPILEFLAGS += \ + -DBINDER_NO_KERNEL_IPC \ + -DBINDER_RPC_SINGLE_THREADED \ + -D__ANDROID_VNDK__ \ + +MODULE_LIBRARY_DEPS += \ + trusty/user/base/lib/libstdc++-trusty \ + trusty/user/base/lib/tipc \ + external/boringssl \ + +include make/library.mk diff --git a/libs/binder/trusty/socket.cpp b/libs/binder/trusty/socket.cpp new file mode 100644 index 0000000000..02df8afb92 --- /dev/null +++ b/libs/binder/trusty/socket.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <log/log.h> + +// On some versions of clang, RpcServer.cpp refuses to link without accept4 +__attribute__((weak)) extern "C" int accept4(int, void*, void*, int) { + LOG_ALWAYS_FATAL("accept4 called on Trusty"); + return 0; +} + +// Placeholder for poll used by FdTrigger +__attribute__((weak)) extern "C" int poll(void*, long, int) { + LOG_ALWAYS_FATAL("poll called on Trusty"); + return 0; +} diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 988132cd1c..da42a96df7 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -2,10 +2,10 @@ LIBNATIVEWINDOW { global: AHardwareBuffer_acquire; AHardwareBuffer_allocate; - AHardwareBuffer_createFromHandle; # llndk # apex + AHardwareBuffer_createFromHandle; # llndk # systemapi AHardwareBuffer_describe; AHardwareBuffer_getId; # introduced=31 - AHardwareBuffer_getNativeHandle; # llndk # apex + AHardwareBuffer_getNativeHandle; # llndk # systemapi AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; AHardwareBuffer_lockAndGetInfo; # introduced=29 @@ -23,18 +23,18 @@ LIBNATIVEWINDOW { ANativeWindow_getBuffersDataSpace; # introduced=28 ANativeWindow_getFormat; ANativeWindow_getHeight; - ANativeWindow_getLastDequeueDuration; # apex # introduced=30 - ANativeWindow_getLastDequeueStartTime; # apex # introduced=30 - ANativeWindow_getLastQueueDuration; # apex # introduced=30 + ANativeWindow_getLastDequeueDuration; # systemapi # introduced=30 + ANativeWindow_getLastDequeueStartTime; # systemapi # introduced=30 + ANativeWindow_getLastQueueDuration; # systemapi # introduced=30 ANativeWindow_getWidth; ANativeWindow_lock; ANativeWindow_query; # llndk ANativeWindow_queryf; # llndk ANativeWindow_queueBuffer; # llndk - ANativeWindow_setCancelBufferInterceptor; # apex # introduced=30 - ANativeWindow_setDequeueBufferInterceptor; # apex # introduced=30 - ANativeWindow_setPerformInterceptor; # apex # introduced=30 - ANativeWindow_setQueueBufferInterceptor; # apex # introduced=30 + ANativeWindow_setCancelBufferInterceptor; # systemapi # introduced=30 + ANativeWindow_setDequeueBufferInterceptor; # systemapi # introduced=30 + ANativeWindow_setPerformInterceptor; # systemapi # introduced=30 + ANativeWindow_setQueueBufferInterceptor; # systemapi # introduced=30 ANativeWindow_release; ANativeWindow_setAutoPrerotation; # llndk ANativeWindow_setAutoRefresh; # llndk @@ -45,7 +45,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersGeometry; ANativeWindow_setBuffersTimestamp; # llndk ANativeWindow_setBuffersTransform; - ANativeWindow_setDequeueTimeout; # apex # introduced=30 + ANativeWindow_setDequeueTimeout; # systemapi # introduced=30 ANativeWindow_setFrameRate; # introduced=30 ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31 ANativeWindow_setSharedBufferMode; # llndk diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 2ac41b1e67..231f825c1f 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -64,7 +64,11 @@ void CursorMotionAccumulator::finishSync() { CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext) : InputMapper(deviceContext) {} -CursorInputMapper::~CursorInputMapper() {} +CursorInputMapper::~CursorInputMapper() { + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE); + } +} uint32_t CursorInputMapper::getSources() { return mSource; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index e60625be89..0afbe11a6b 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -755,7 +755,11 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, // We must support R8G8B8A8 std::vector<VkSurfaceFormatKHR> all_formats = { {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, - {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}}; + {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}, + // Also allow to use PASS_THROUGH + HAL_DATASPACE_ARBITRARY + {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT}, + {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT}, + }; if (colorspace_ext) { all_formats.emplace_back(VkSurfaceFormatKHR{ @@ -777,12 +781,16 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, if (AHardwareBuffer_isSupported(&desc)) { all_formats.emplace_back(VkSurfaceFormatKHR{ VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_PASS_THROUGH_EXT}); } desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; if (AHardwareBuffer_isSupported(&desc)) { all_formats.emplace_back(VkSurfaceFormatKHR{ VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + all_formats.emplace_back(VkSurfaceFormatKHR{ + VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_PASS_THROUGH_EXT}); if (wide_color_support) { all_formats.emplace_back( VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT, @@ -798,6 +806,9 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, all_formats.emplace_back( VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}); + all_formats.emplace_back( + VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32, + VK_COLOR_SPACE_PASS_THROUGH_EXT}); if (wide_color_support) { all_formats.emplace_back( VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32, |