diff options
40 files changed, 1065 insertions, 473 deletions
diff --git a/.clang-format b/.clang-format index 6725a1fde8..f63f670adc 100644 --- a/.clang-format +++ b/.clang-format @@ -12,3 +12,6 @@ IndentWidth: 4 PenaltyBreakBeforeFirstCallParameter: 100000 SpacesBeforeTrailingComments: 1 IncludeBlocks: Preserve + +DerivePointerAlignment: false +PointerAlignment: Left diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index ff73c9499f..e54f9d3df7 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -353,8 +353,16 @@ bool ListCommand::addEntryWithInstance(const TableEntry& entry, return false; } + auto vintfFqInstance = vintf::FqInstance::from(fqInstance.string()); + if (!vintfFqInstance.has_value()) { + err() << "Unable to convert " << fqInstance.string() << " to vintf::FqInstance" + << std::endl; + return false; + } + std::string e; - if (!manifest->insertInstance(fqInstance, entry.transport, arch, vintf::HalFormat::HIDL, &e)) { + if (!manifest->insertInstance(*vintfFqInstance, entry.transport, arch, vintf::HalFormat::HIDL, + &e)) { err() << "Warning: Cannot insert '" << fqInstance.string() << ": " << e << std::endl; return false; } diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index e70a98d2c9..150bde8153 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -76,7 +76,6 @@ cc_defaults { srcs: [ "Binder.cpp", - "BinderRecordReplay.cpp", "BpBinder.cpp", "Debug.cpp", "FdTrigger.cpp", @@ -84,6 +83,7 @@ cc_defaults { "IResultReceiver.cpp", "Parcel.cpp", "ParcelFileDescriptor.cpp", + "RecordedTransaction.cpp", "RpcSession.cpp", "RpcServer.cpp", "RpcState.cpp", @@ -195,18 +195,25 @@ cc_defaults { ], } -cc_library_shared { - name: "libbinder_on_trusty_mock", - defaults: ["libbinder_common_defaults"], +cc_library_headers { + name: "trusty_mock_headers", + host_supported: true, - srcs: [ - // Trusty-specific files - "trusty/logging.cpp", - "trusty/OS.cpp", - "trusty/RpcServerTrusty.cpp", - "trusty/RpcTransportTipcTrusty.cpp", - "trusty/TrustyStatus.cpp", - "trusty/socket.cpp", + export_include_dirs: [ + "trusty/include", + "trusty/include_mock", + ], + + visibility: [ + ":__subpackages__", + ], +} + +cc_defaults { + name: "trusty_mock_defaults", + + header_libs: [ + "trusty_mock_headers", ], cflags: [ @@ -227,16 +234,29 @@ cc_library_shared { ], rtti: false, - local_include_dirs: [ - "trusty/include", - "trusty/include_mock", - ], - visibility: [ ":__subpackages__", ], } +cc_library_shared { + name: "libbinder_on_trusty_mock", + defaults: [ + "libbinder_common_defaults", + "trusty_mock_defaults", + ], + + srcs: [ + // Trusty-specific files + "trusty/logging.cpp", + "trusty/OS.cpp", + "trusty/RpcServerTrusty.cpp", + "trusty/RpcTransportTipcTrusty.cpp", + "trusty/TrustyStatus.cpp", + "trusty/socket.cpp", + ], +} + cc_defaults { name: "libbinder_kernel_defaults", srcs: [ diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 5e725a91f2..3e49656575 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -21,13 +21,13 @@ #include <android-base/logging.h> #include <android-base/unique_fd.h> -#include <binder/BinderRecordReplay.h> #include <binder/BpBinder.h> #include <binder/IInterface.h> #include <binder/IPCThreadState.h> #include <binder/IResultReceiver.h> #include <binder/IShellCallback.h> #include <binder/Parcel.h> +#include <binder/RecordedTransaction.h> #include <binder/RpcServer.h> #include <cutils/compiler.h> #include <private/android_filesystem_config.h> @@ -407,11 +407,11 @@ status_t BBinder::transact( AutoMutex lock(e->mLock); if (mRecordingOn) { Parcel emptyReply; - auto transaction = - android::binder::debug::RecordedTransaction::fromDetails(code, flags, data, - reply ? *reply - : emptyReply, - err); + timespec ts; + timespec_get(&ts, TIME_UTC); + auto transaction = android::binder::debug::RecordedTransaction:: + fromDetails(getInterfaceDescriptor(), code, flags, ts, data, + reply ? *reply : emptyReply, err); if (transaction) { if (status_t err = transaction->dumpToFile(e->mRecordingFd); err != NO_ERROR) { LOG(INFO) << "Failed to dump RecordedTransaction to file with error " << err; diff --git a/libs/binder/BinderRecordReplay.cpp b/libs/binder/BinderRecordReplay.cpp deleted file mode 100644 index 94637853f9..0000000000 --- a/libs/binder/BinderRecordReplay.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* - * 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 <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/unique_fd.h> -#include <binder/BinderRecordReplay.h> -#include <algorithm> - -using android::Parcel; -using android::base::borrowed_fd; -using android::base::unique_fd; -using android::binder::debug::RecordedTransaction; - -#define PADDING8(s) ((8 - (s) % 8) % 8) - -static_assert(PADDING8(0) == 0); -static_assert(PADDING8(1) == 7); -static_assert(PADDING8(7) == 1); -static_assert(PADDING8(8) == 0); - -// Transactions are sequentially recorded to a file descriptor. -// -// An individual RecordedTransaction is written with the following format: -// -// WARNING: Though the following format is designed to be stable and -// extensible, it is under active development and should be considered -// unstable until this warning is removed. -// -// A RecordedTransaction is written to a file as a sequence of Chunks. -// -// A Chunk consists of a ChunkDescriptor, Data, and Padding. -// -// Data and Padding may each be zero-length as specified by the -// ChunkDescriptor. -// -// The ChunkDescriptor identifies the type of data in the chunk, the size of -// the data in bytes, and the number of zero-bytes padding to land on an -// 8-byte boundary by the end of the Chunk. -// -// ┌───────────────────────────┐ -// │Chunk │ -// │┌─────────────────────────┐│ -// ││ChunkDescriptor ││ -// ││┌───────────┬───────────┐││ -// │││chunkType │paddingSize│││ -// │││uint32_t │uint32_t ├┼┼───┐ -// ││├───────────┴───────────┤││ │ -// │││dataSize │││ │ -// │││uint64_t ├┼┼─┐ │ -// ││└───────────────────────┘││ │ │ -// │└─────────────────────────┘│ │ │ -// │┌─────────────────────────┐│ │ │ -// ││Data ││ │ │ -// ││bytes * dataSize │◀─┘ │ -// │└─────────────────────────┘│ │ -// │┌─────────────────────────┐│ │ -// ││Padding ││ │ -// ││bytes * paddingSize │◀───┘ -// │└─────────────────────────┘│ -// └───────────────────────────┘ -// -// A RecordedTransaction is written as a Header Chunk with fields about the -// transaction, a Data Parcel chunk, a Reply Parcel Chunk, and an End Chunk. -// ┌──────────────────────┐ -// │ Header Chunk │ -// ├──────────────────────┤ -// │ Sent Parcel Chunk │ -// ├──────────────────────┤ -// │ Reply Parcel Chunk │ -// ├──────────────────────┤ -// ║ End Chunk ║ -// ╚══════════════════════╝ -// -// On reading a RecordedTransaction, an unrecognized chunk is skipped using -// the size information in the ChunkDescriptor. Chunks are read and either -// assimilated or skipped until an End Chunk is encountered. This has three -// notable implications: -// -// 1. Older and newer implementations should be able to read one another's -// Transactions, though there will be loss of information. -// 2. With the exception of the End Chunk, Chunks can appear in any -// order and even repeat, though this is not recommended. -// 3. If any Chunk is repeated, old values will be overwritten by versions -// encountered later in the file. -// -// No effort is made to ensure the expected chunks are present. A single -// End Chunk may therefore produce a empty, meaningless RecordedTransaction. - -RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept { - mHeader = {t.getCode(), t.getFlags(), t.getReturnedStatus(), t.getVersion()}; - mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); - mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); -} - -std::optional<RecordedTransaction> RecordedTransaction::fromDetails(uint32_t code, uint32_t flags, - const Parcel& dataParcel, - const Parcel& replyParcel, - status_t err) { - RecordedTransaction t; - t.mHeader = {code, flags, static_cast<int32_t>(err), - dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0)}; - - if (t.mSent.setData(dataParcel.data(), dataParcel.dataSize()) != android::NO_ERROR) { - LOG(INFO) << "Failed to set sent parcel data."; - return std::nullopt; - } - - if (t.mReply.setData(replyParcel.data(), replyParcel.dataSize()) != android::NO_ERROR) { - LOG(INFO) << "Failed to set reply parcel data."; - return std::nullopt; - } - - return std::optional<RecordedTransaction>(std::move(t)); -} - -enum { - HEADER_CHUNK = 0x00000001, - DATA_PARCEL_CHUNK = 0x00000002, - REPLY_PARCEL_CHUNK = 0x00000003, - INVALID_CHUNK = 0x00fffffe, - END_CHUNK = 0x00ffffff, -}; - -struct ChunkDescriptor { - uint32_t chunkType = 0; - uint32_t padding = 0; - uint32_t dataSize = 0; - uint32_t reserved = 0; // Future checksum -}; - -static android::status_t readChunkDescriptor(borrowed_fd fd, ChunkDescriptor* chunkOut) { - if (!android::base::ReadFully(fd, chunkOut, sizeof(ChunkDescriptor))) { - LOG(INFO) << "Failed to read Chunk Descriptor from fd " << fd.get(); - return android::UNKNOWN_ERROR; - } - if (PADDING8(chunkOut->dataSize) != chunkOut->padding) { - chunkOut->chunkType = INVALID_CHUNK; - LOG(INFO) << "Chunk data and padding sizes do not align." << fd.get(); - return android::BAD_VALUE; - } - return android::NO_ERROR; -} - -std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd& fd) { - RecordedTransaction t; - ChunkDescriptor chunk; - - do { - if (NO_ERROR != readChunkDescriptor(fd, &chunk)) { - LOG(INFO) << "Failed to read chunk descriptor."; - return std::nullopt; - } - switch (chunk.chunkType) { - case HEADER_CHUNK: { - if (chunk.dataSize != static_cast<uint32_t>(sizeof(TransactionHeader))) { - LOG(INFO) << "Header Chunk indicated size " << chunk.dataSize << "; Expected " - << sizeof(TransactionHeader) << "."; - return std::nullopt; - } - if (!android::base::ReadFully(fd, &t.mHeader, chunk.dataSize)) { - LOG(INFO) << "Failed to read transactionHeader from fd " << fd.get(); - return std::nullopt; - } - break; - } - case DATA_PARCEL_CHUNK: { - std::vector<uint8_t> bytes; - bytes.resize(chunk.dataSize); - if (!android::base::ReadFully(fd, bytes.data(), chunk.dataSize)) { - LOG(INFO) << "Failed to read sent parcel data from fd " << fd.get(); - return std::nullopt; - } - if (t.mSent.setData(bytes.data(), chunk.dataSize) != android::NO_ERROR) { - LOG(INFO) << "Failed to set sent parcel data."; - return std::nullopt; - } - lseek(fd.get(), chunk.padding, SEEK_CUR); - break; - } - case REPLY_PARCEL_CHUNK: { - std::vector<uint8_t> bytes; - bytes.resize(chunk.dataSize); - if (!android::base::ReadFully(fd, bytes.data(), chunk.dataSize)) { - LOG(INFO) << "Failed to read reply parcel data from fd " << fd.get(); - return std::nullopt; - } - if (t.mReply.setData(bytes.data(), chunk.dataSize) != android::NO_ERROR) { - LOG(INFO) << "Failed to set reply parcel data."; - return std::nullopt; - } - lseek(fd.get(), chunk.padding, SEEK_CUR); - break; - } - case INVALID_CHUNK: - LOG(INFO) << "Invalid chunk."; - return std::nullopt; - case END_CHUNK: - LOG(INFO) << "Read end chunk"; - FALLTHROUGH_INTENDED; - default: - // Unrecognized or skippable chunk - lseek(fd.get(), chunk.dataSize + chunk.padding, SEEK_CUR); - break; - } - } while (chunk.chunkType != END_CHUNK); - - return std::optional<RecordedTransaction>(std::move(t)); -} - -android::status_t RecordedTransaction::writeChunk(borrowed_fd fd, uint32_t chunkType, - size_t byteCount, const uint8_t* data) const { - // Write Chunk Descriptor - // - Chunk Type - if (!android::base::WriteFully(fd, &chunkType, sizeof(uint32_t))) { - LOG(INFO) << "Failed to write chunk header to fd " << fd.get(); - return UNKNOWN_ERROR; - } - // - Chunk Data Padding Size - uint32_t additionalPaddingCount = static_cast<uint32_t>(PADDING8(byteCount)); - if (!android::base::WriteFully(fd, &additionalPaddingCount, sizeof(uint32_t))) { - LOG(INFO) << "Failed to write chunk padding size to fd " << fd.get(); - return UNKNOWN_ERROR; - } - // - Chunk Data Size - uint64_t byteCountToWrite = (uint64_t)byteCount; - if (!android::base::WriteFully(fd, &byteCountToWrite, sizeof(uint64_t))) { - LOG(INFO) << "Failed to write chunk size to fd " << fd.get(); - return UNKNOWN_ERROR; - } - if (byteCount == 0) { - return NO_ERROR; - } - - if (!android::base::WriteFully(fd, data, byteCount)) { - LOG(INFO) << "Failed to write chunk data to fd " << fd.get(); - return UNKNOWN_ERROR; - } - - const uint8_t zeros[7] = {0}; - if (!android::base::WriteFully(fd, zeros, additionalPaddingCount)) { - LOG(INFO) << "Failed to write chunk padding to fd " << fd.get(); - return UNKNOWN_ERROR; - } - return NO_ERROR; -} - -android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { - if (NO_ERROR != - writeChunk(fd, HEADER_CHUNK, sizeof(TransactionHeader), - reinterpret_cast<const uint8_t*>(&mHeader))) { - LOG(INFO) << "Failed to write transactionHeader to fd " << fd.get(); - return UNKNOWN_ERROR; - } - if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataSize(), mSent.data())) { - LOG(INFO) << "Failed to write sent Parcel to fd " << fd.get(); - return UNKNOWN_ERROR; - } - if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataSize(), mReply.data())) { - LOG(INFO) << "Failed to write reply Parcel to fd " << fd.get(); - return UNKNOWN_ERROR; - } - if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) { - LOG(INFO) << "Failed to write end chunk to fd " << fd.get(); - return UNKNOWN_ERROR; - } - return NO_ERROR; -} - -uint32_t RecordedTransaction::getCode() const { - return mHeader.code; -} - -uint32_t RecordedTransaction::getFlags() const { - return mHeader.flags; -} - -int32_t RecordedTransaction::getReturnedStatus() const { - return mHeader.statusReturned; -} - -uint32_t RecordedTransaction::getVersion() const { - return mHeader.version; -} - -const Parcel& RecordedTransaction::getDataParcel() const { - return mSent; -} - -const Parcel& RecordedTransaction::getReplyParcel() const { - return mReply; -} diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 1c470a11d3..d03326eb04 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -388,7 +388,7 @@ status_t BpBinder::linkToDeath( { if (isRpcBinder()) { if (rpcSession()->getMaxIncomingThreads() < 1) { - LOG_ALWAYS_FATAL("Cannot register a DeathRecipient without any incoming connections."); + ALOGE("Cannot register a DeathRecipient without any incoming connections."); return INVALID_OPERATION; } } else if constexpr (!kEnableKernelIpc) { diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 6d64e1ed3e..da58251149 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1221,6 +1221,10 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) return NO_ERROR; } + ALOGE_IF(mProcess->mDriverFD >= 0, + "Driver returned error (%s). This is a bug in either libbinder or the driver. This " + "thread's connection to %s will no longer work.", + statusToString(err).c_str(), mProcess->mDriverName.c_str()); return err; } diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp new file mode 100644 index 0000000000..5406205b2b --- /dev/null +++ b/libs/binder/RecordedTransaction.cpp @@ -0,0 +1,363 @@ +/* + * 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 <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/unique_fd.h> +#include <binder/RecordedTransaction.h> +#include <sys/mman.h> +#include <algorithm> + +using android::Parcel; +using android::base::borrowed_fd; +using android::base::unique_fd; +using android::binder::debug::RecordedTransaction; + +#define PADDING8(s) ((8 - (s) % 8) % 8) + +static_assert(PADDING8(0) == 0); +static_assert(PADDING8(1) == 7); +static_assert(PADDING8(7) == 1); +static_assert(PADDING8(8) == 0); + +// Transactions are sequentially recorded to a file descriptor. +// +// An individual RecordedTransaction is written with the following format: +// +// WARNING: Though the following format is designed to be stable and +// extensible, it is under active development and should be considered +// unstable until this warning is removed. +// +// A RecordedTransaction is written to a file as a sequence of Chunks. +// +// A Chunk consists of a ChunkDescriptor, Data, Padding, and a Checksum. +// +// The ChunkDescriptor identifies the type of Data in the chunk, and the size +// of the Data. +// +// The Data may be any uint32 number of bytes in length in [0-0xfffffff0]. +// +// Padding is between [0-7] zero-bytes after the Data such that the Chunk ends +// on an 8-byte boundary. The ChunkDescriptor's dataSize does not include the +// size of Padding. +// +// The checksum is a 64-bit wide XOR of all previous data from the start of the +// ChunkDescriptor to the end of Padding. +// +// ┌───────────────────────────┐ +// │Chunk │ +// │┌────────────────────────┐ │ +// ││ChunkDescriptor │ │ +// ││┌───────────┬──────────┐│ │ +// │││chunkType │dataSize ├┼─┼─┐ +// │││uint32_t │uint32_t ││ │ │ +// ││└───────────┴──────────┘│ │ │ +// │└────────────────────────┘ │ │ +// │┌─────────────────────────┐│ │ +// ││Data ││ │ +// ││bytes * dataSize │◀─┘ +// ││ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤│ +// ││ Padding ││ +// │└───┴─────────────────────┘│ +// │┌─────────────────────────┐│ +// ││checksum ││ +// ││uint64_t ││ +// │└─────────────────────────┘│ +// └───────────────────────────┘ +// +// A RecordedTransaction is written as a Header Chunk with fields about the +// transaction, a Data Parcel chunk, a Reply Parcel Chunk, and an End Chunk. +// ┌──────────────────────┐ +// │ Header Chunk │ +// ├──────────────────────┤ +// │ Sent Parcel Chunk │ +// ├──────────────────────┤ +// │ Reply Parcel Chunk │ +// ├──────────────────────┤ +// ║ End Chunk ║ +// ╚══════════════════════╝ +// +// On reading a RecordedTransaction, an unrecognized chunk is checksummed +// then skipped according to size information in the ChunkDescriptor. Chunks +// are read and either assimilated or skipped until an End Chunk is +// encountered. This has three notable implications: +// +// 1. Older and newer implementations should be able to read one another's +// Transactions, though there will be loss of information. +// 2. With the exception of the End Chunk, Chunks can appear in any order +// and even repeat, though this is not recommended. +// 3. If any Chunk is repeated, old values will be overwritten by versions +// encountered later in the file. +// +// No effort is made to ensure the expected chunks are present. A single +// End Chunk may therefore produce an empty, meaningless RecordedTransaction. + +RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept { + mData = t.mData; + mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); + mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); +} + +std::optional<RecordedTransaction> RecordedTransaction::fromDetails( + const String16& interfaceName, uint32_t code, uint32_t flags, timespec timestamp, + const Parcel& dataParcel, const Parcel& replyParcel, status_t err) { + RecordedTransaction t; + t.mData.mHeader = {code, + flags, + static_cast<int32_t>(err), + dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0), + static_cast<int64_t>(timestamp.tv_sec), + static_cast<int32_t>(timestamp.tv_nsec), + 0}; + + t.mData.mInterfaceName = String8(interfaceName); + if (interfaceName.size() != t.mData.mInterfaceName.bytes()) { + LOG(ERROR) << "Interface Name is not valid. Contains characters that aren't single byte " + "utf-8: " + << interfaceName; + return std::nullopt; + } + + if (t.mSent.setData(dataParcel.data(), dataParcel.dataSize()) != android::NO_ERROR) { + LOG(ERROR) << "Failed to set sent parcel data."; + return std::nullopt; + } + + if (t.mReply.setData(replyParcel.data(), replyParcel.dataSize()) != android::NO_ERROR) { + LOG(ERROR) << "Failed to set reply parcel data."; + return std::nullopt; + } + + return std::optional<RecordedTransaction>(std::move(t)); +} + +enum { + HEADER_CHUNK = 1, + DATA_PARCEL_CHUNK = 2, + REPLY_PARCEL_CHUNK = 3, + INTERFACE_NAME_CHUNK = 4, + END_CHUNK = 0x00ffffff, +}; + +struct ChunkDescriptor { + uint32_t chunkType = 0; + uint32_t dataSize = 0; +}; +static_assert(sizeof(ChunkDescriptor) % 8 == 0); + +constexpr uint32_t kMaxChunkDataSize = 0xfffffff0; +typedef uint64_t transaction_checksum_t; + +static android::status_t readChunkDescriptor(borrowed_fd fd, ChunkDescriptor* chunkOut, + transaction_checksum_t* sum) { + if (!android::base::ReadFully(fd, chunkOut, sizeof(ChunkDescriptor))) { + LOG(ERROR) << "Failed to read Chunk Descriptor from fd " << fd.get(); + return android::UNKNOWN_ERROR; + } + + *sum ^= *reinterpret_cast<transaction_checksum_t*>(chunkOut); + return android::NO_ERROR; +} + +std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd& fd) { + RecordedTransaction t; + ChunkDescriptor chunk; + const long pageSize = sysconf(_SC_PAGE_SIZE); + do { + transaction_checksum_t checksum = 0; + if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) { + LOG(ERROR) << "Failed to read chunk descriptor."; + return std::nullopt; + } + off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); + off_t mmapPageAlignedStart = (fdCurrentPosition / pageSize) * pageSize; + off_t mmapPayloadStartOffset = fdCurrentPosition - mmapPageAlignedStart; + + if (chunk.dataSize > kMaxChunkDataSize) { + LOG(ERROR) << "Chunk data exceeds maximum size."; + return std::nullopt; + } + + size_t chunkPayloadSize = + chunk.dataSize + PADDING8(chunk.dataSize) + sizeof(transaction_checksum_t); + + if (PADDING8(chunkPayloadSize) != 0) { + LOG(ERROR) << "Invalid chunk size, not aligned " << chunkPayloadSize; + return std::nullopt; + } + + transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>( + mmap(NULL, chunkPayloadSize + mmapPayloadStartOffset, PROT_READ, MAP_SHARED, + fd.get(), mmapPageAlignedStart)); + payloadMap += mmapPayloadStartOffset / + sizeof(transaction_checksum_t); // Skip chunk descriptor and required mmap + // page-alignment + if (payloadMap == MAP_FAILED) { + LOG(ERROR) << "Memory mapping failed for fd " << fd.get() << ": " << errno << " " + << strerror(errno); + return std::nullopt; + } + for (size_t checksumIndex = 0; + checksumIndex < chunkPayloadSize / sizeof(transaction_checksum_t); checksumIndex++) { + checksum ^= payloadMap[checksumIndex]; + } + if (checksum != 0) { + LOG(ERROR) << "Checksum failed."; + return std::nullopt; + } + lseek(fd.get(), chunkPayloadSize, SEEK_CUR); + + switch (chunk.chunkType) { + case HEADER_CHUNK: { + if (chunk.dataSize != static_cast<uint32_t>(sizeof(TransactionHeader))) { + LOG(ERROR) << "Header Chunk indicated size " << chunk.dataSize << "; Expected " + << sizeof(TransactionHeader) << "."; + return std::nullopt; + } + t.mData.mHeader = *reinterpret_cast<TransactionHeader*>(payloadMap); + break; + } + case INTERFACE_NAME_CHUNK: { + t.mData.mInterfaceName.setTo(reinterpret_cast<char*>(payloadMap), chunk.dataSize); + break; + } + case DATA_PARCEL_CHUNK: { + if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap), + chunk.dataSize) != android::NO_ERROR) { + LOG(ERROR) << "Failed to set sent parcel data."; + return std::nullopt; + } + break; + } + case REPLY_PARCEL_CHUNK: { + if (t.mReply.setData(reinterpret_cast<const unsigned char*>(payloadMap), + chunk.dataSize) != android::NO_ERROR) { + LOG(ERROR) << "Failed to set reply parcel data."; + return std::nullopt; + } + break; + } + case END_CHUNK: + break; + default: + LOG(INFO) << "Unrecognized chunk."; + continue; + } + } while (chunk.chunkType != END_CHUNK); + + return std::optional<RecordedTransaction>(std::move(t)); +} + +android::status_t RecordedTransaction::writeChunk(borrowed_fd fd, uint32_t chunkType, + size_t byteCount, const uint8_t* data) const { + if (byteCount > kMaxChunkDataSize) { + LOG(ERROR) << "Chunk data exceeds maximum size"; + return BAD_VALUE; + } + ChunkDescriptor descriptor = {.chunkType = chunkType, + .dataSize = static_cast<uint32_t>(byteCount)}; + // Prepare Chunk content as byte * + const std::byte* descriptorBytes = reinterpret_cast<const std::byte*>(&descriptor); + const std::byte* dataBytes = reinterpret_cast<const std::byte*>(data); + + // Add Chunk to intermediate buffer, except checksum + std::vector<std::byte> buffer; + buffer.insert(buffer.end(), descriptorBytes, descriptorBytes + sizeof(ChunkDescriptor)); + buffer.insert(buffer.end(), dataBytes, dataBytes + byteCount); + std::byte zero{0}; + buffer.insert(buffer.end(), PADDING8(byteCount), zero); + + // Calculate checksum from buffer + transaction_checksum_t* checksumData = reinterpret_cast<transaction_checksum_t*>(buffer.data()); + transaction_checksum_t checksumValue = 0; + for (size_t idx = 0; idx < (buffer.size() / sizeof(transaction_checksum_t)); idx++) { + checksumValue ^= checksumData[idx]; + } + + // Write checksum to buffer + std::byte* checksumBytes = reinterpret_cast<std::byte*>(&checksumValue); + buffer.insert(buffer.end(), checksumBytes, checksumBytes + sizeof(transaction_checksum_t)); + + // Write buffer to file + if (!android::base::WriteFully(fd, buffer.data(), buffer.size())) { + LOG(ERROR) << "Failed to write chunk fd " << fd.get(); + return UNKNOWN_ERROR; + } + return NO_ERROR; +} + +android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { + if (NO_ERROR != + writeChunk(fd, HEADER_CHUNK, sizeof(TransactionHeader), + reinterpret_cast<const uint8_t*>(&(mData.mHeader)))) { + LOG(ERROR) << "Failed to write transactionHeader to fd " << fd.get(); + return UNKNOWN_ERROR; + } + if (NO_ERROR != + writeChunk(fd, INTERFACE_NAME_CHUNK, mData.mInterfaceName.size() * sizeof(uint8_t), + reinterpret_cast<const uint8_t*>(mData.mInterfaceName.string()))) { + LOG(INFO) << "Failed to write Interface Name Chunk to fd " << fd.get(); + return UNKNOWN_ERROR; + } + + if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataSize(), mSent.data())) { + LOG(ERROR) << "Failed to write sent Parcel to fd " << fd.get(); + return UNKNOWN_ERROR; + } + if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataSize(), mReply.data())) { + LOG(ERROR) << "Failed to write reply Parcel to fd " << fd.get(); + return UNKNOWN_ERROR; + } + if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) { + LOG(ERROR) << "Failed to write end chunk to fd " << fd.get(); + return UNKNOWN_ERROR; + } + return NO_ERROR; +} + +const android::String8& RecordedTransaction::getInterfaceName() const { + return mData.mInterfaceName; +} + +uint32_t RecordedTransaction::getCode() const { + return mData.mHeader.code; +} + +uint32_t RecordedTransaction::getFlags() const { + return mData.mHeader.flags; +} + +int32_t RecordedTransaction::getReturnedStatus() const { + return mData.mHeader.statusReturned; +} + +timespec RecordedTransaction::getTimestamp() const { + time_t sec = mData.mHeader.timestampSeconds; + int32_t nsec = mData.mHeader.timestampNanoseconds; + return (timespec){.tv_sec = sec, .tv_nsec = nsec}; +} + +uint32_t RecordedTransaction::getVersion() const { + return mData.mHeader.version; +} + +const Parcel& RecordedTransaction::getDataParcel() const { + return mSent; +} + +const Parcel& RecordedTransaction::getReplyParcel() const { + return mReply; +} diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 342e4a389a..180c67c271 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -52,6 +52,9 @@ "name": "memunreachable_binder_test" }, { + "name": "resolv_integration_test" + }, + { "name": "libbinderthreadstateutils_test" }, { diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 08dbd13bf4..d960a0b894 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -106,7 +106,7 @@ public: const sp<IBinder>& keepAliveBinder); // Start recording transactions to the unique_fd in data. - // See BinderRecordReplay.h for more details. + // See RecordedTransaction.h for more details. [[nodiscard]] status_t startRecordingTransactions(const Parcel& data); // Stop the current recording. [[nodiscard]] status_t stopRecordingTransactions(); diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 57e103d39e..5496d61b70 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -91,7 +91,7 @@ public: std::optional<int32_t> getDebugBinderHandle() const; // Start recording transactions to the unique_fd. - // See BinderRecordReplay.h for more details. + // See RecordedTransaction.h for more details. status_t startRecordingBinder(const android::base::unique_fd& fd); // Stop the current recording. status_t stopRecordingBinder(); diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h index 9896fd7a51..08d8e43106 100644 --- a/libs/binder/include/binder/ParcelFileDescriptor.h +++ b/libs/binder/include/binder/ParcelFileDescriptor.h @@ -42,6 +42,7 @@ public: android::status_t writeToParcel(android::Parcel* parcel) const override; android::status_t readFromParcel(const android::Parcel* parcel) override; + inline std::string toString() const { return "ParcelFileDescriptor:" + std::to_string(get()); } inline bool operator!=(const ParcelFileDescriptor& rhs) const { return mFd.get() != rhs.mFd.get(); } diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h index 88790a803b..40fd30ae3f 100644 --- a/libs/binder/include/binder/ParcelableHolder.h +++ b/libs/binder/include/binder/ParcelableHolder.h @@ -111,6 +111,11 @@ public: Stability getStability() const override { return mStability; } + inline std::string toString() const { + return "ParcelableHolder:" + + (mParcelableName ? std::string(String8(mParcelableName.value()).c_str()) + : "<parceled>"); + } inline bool operator!=(const ParcelableHolder& rhs) const { return this != &rhs; } diff --git a/libs/binder/include/binder/BinderRecordReplay.h b/libs/binder/include/binder/RecordedTransaction.h index 609e5be8d1..4966330046 100644 --- a/libs/binder/include/binder/BinderRecordReplay.h +++ b/libs/binder/include/binder/RecordedTransaction.h @@ -26,23 +26,26 @@ namespace binder::debug { // Warning: Transactions are sequentially recorded to the file descriptor in a // non-stable format. A detailed description of the recording format can be found in -// BinderRecordReplay.cpp. +// RecordedTransaction.cpp. class RecordedTransaction { public: // Filled with the first transaction from fd. static std::optional<RecordedTransaction> fromFile(const android::base::unique_fd& fd); // Filled with the arguments. - static std::optional<RecordedTransaction> fromDetails(uint32_t code, uint32_t flags, - const Parcel& data, const Parcel& reply, - status_t err); + static std::optional<RecordedTransaction> fromDetails(const String16& interfaceName, + uint32_t code, uint32_t flags, + timespec timestamp, const Parcel& data, + const Parcel& reply, status_t err); RecordedTransaction(RecordedTransaction&& t) noexcept; [[nodiscard]] status_t dumpToFile(const android::base::unique_fd& fd) const; + const String8& getInterfaceName() const; uint32_t getCode() const; uint32_t getFlags() const; int32_t getReturnedStatus() const; + timespec getTimestamp() const; uint32_t getVersion() const; const Parcel& getDataParcel() const; const Parcel& getReplyParcel() const; @@ -60,12 +63,19 @@ private: uint32_t flags = 0; int32_t statusReturned = 0; uint32_t version = 0; // !0 iff Rpc + int64_t timestampSeconds = 0; + int32_t timestampNanoseconds = 0; + int32_t reserved = 0; }; #pragma clang diagnostic pop - static_assert(sizeof(TransactionHeader) == 16); + static_assert(sizeof(TransactionHeader) == 32); static_assert(sizeof(TransactionHeader) % 8 == 0); - TransactionHeader mHeader; + struct MovableData { // movable + TransactionHeader mHeader; + String8 mInterfaceName; + }; + MovableData mData; Parcel mSent; Parcel mReply; }; diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h index 2a00736bc3..9b0d222147 100644 --- a/libs/binder/ndk/include_cpp/android/binder_to_string.h +++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h @@ -49,12 +49,17 @@ #include <android/binder_interface_utils.h> #include <android/binder_parcelable_utils.h> #define HAS_NDK_INTERFACE -#else +#endif + +// TODO: some things include libbinder without having access to libbase. This is +// due to frameworks/native/include, which symlinks to libbinder headers, so even +// though we don't use it here, we detect a different header, so that we are more +// confident libbase will be included +#if __has_include(<binder/RpcSession.h>) #include <binder/IBinder.h> #include <binder/IInterface.h> -#include <binder/ParcelFileDescriptor.h> -#include <binder/ParcelableHolder.h> -#endif //_has_include +#define HAS_CPP_INTERFACE +#endif namespace android { namespace internal { @@ -104,10 +109,12 @@ class IsPointerLike { IsInstantiationOf<_U, sp>::value || // for IBinder and interface types in the C++ // backend #endif - IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the - // C++/NDK backends - IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the - // NDK backends + IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the + // C++/NDK backends + IsInstantiationOf<_U, std::unique_ptr>::value || // for @nullable(heap=true) + // in C++/NDK backends + IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the + // NDK backends std::true_type> _test(int); @@ -134,19 +141,19 @@ class IsIterable { template <typename _T> class ToEmptyString { template <typename _U> - static std::enable_if_t< + static std::enable_if_t<false #ifdef HAS_NDK_INTERFACE - std::is_base_of_v<::ndk::ICInterface, _U> + || std::is_base_of_v<::ndk::ICInterface, _U> #if __ANDROID_API__ >= 31 - || std::is_same_v<::ndk::AParcelableHolder, _U> + || std::is_same_v<::ndk::AParcelableHolder, _U> #endif -#else - std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> || - std::is_same_v<os::ParcelFileDescriptor, _U> || - std::is_same_v<os::ParcelableHolder, _U> +#endif // HAS_NDK_INTERFACE +#ifdef HAS_CPP_INTERFACE + || std::is_base_of_v<IInterface, _U> || + std::is_same_v<IBinder, _U> #endif - , - std::true_type> + , + std::true_type> _test(int); template <typename _U> static std::false_type _test(...); @@ -155,6 +162,11 @@ class ToEmptyString { enum { value = decltype(_test<_T>(0))::value }; }; +template <typename _T> +struct TypeDependentFalse { + enum { value = false }; +}; + } // namespace details template <typename _T> @@ -214,11 +226,27 @@ std::string ToString(const _T& t) { out << "]"; return out.str(); } else { - return "{no toString() implemented}"; + static_assert(details::TypeDependentFalse<_T>::value, "no toString implemented, huh?"); } } } // namespace internal } // namespace android +#ifdef HAS_STRONG_POINTER +#undef HAS_STRONG_POINTER +#endif + +#ifdef HAS_STRING16 +#undef HAS_STRING16 +#endif + +#ifdef HAS_NDK_INTERFACE +#undef HAS_NDK_INTERFACE +#endif + +#ifdef HAS_CPP_INTERFACE +#undef HAS_CPP_INTERFACE +#endif + /** @} */ diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 86930229ce..94f72d96f6 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -700,6 +700,9 @@ binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t s return STATUS_BAD_VALUE; } const uint8_t* internalBuffer = parcel->get()->data(); + if (internalBuffer == nullptr) { + return STATUS_UNEXPECTED_NULL; + } memcpy(buffer, internalBuffer + start, len); return STATUS_OK; } diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 5db3187320..bab4e73a4c 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -336,6 +336,29 @@ cc_test { ], } +cc_binary { + name: "binderRpcTestService_on_trusty_mock", + defaults: [ + "trusty_mock_defaults", + ], + + srcs: [ + "binderRpcTestCommon.cpp", + "binderRpcTestServiceTrusty.cpp", + ], + + shared_libs: [ + "libbinder_on_trusty_mock", + "libbase", + "libutils", + "libcutils", + ], + + static_libs: [ + "binderRpcTestIface-cpp", + ], +} + cc_test { name: "binderRpcTest", defaults: [ @@ -347,6 +370,7 @@ cc_test { // Add the Trusty mock library as a fake dependency so it gets built required: [ "libbinder_on_trusty_mock", + "binderRpcTestService_on_trusty_mock", ], } diff --git a/libs/binder/tests/binderRecordedTransactionTest.cpp b/libs/binder/tests/binderRecordedTransactionTest.cpp index 67e482d2fb..2f5c8c6886 100644 --- a/libs/binder/tests/binderRecordedTransactionTest.cpp +++ b/libs/binder/tests/binderRecordedTransactionTest.cpp @@ -14,8 +14,9 @@ * limitations under the License. */ -#include <binder/BinderRecordReplay.h> +#include <binder/RecordedTransaction.h> #include <gtest/gtest.h> +#include <utils/Errors.h> using android::Parcel; using android::status_t; @@ -23,12 +24,16 @@ using android::base::unique_fd; using android::binder::debug::RecordedTransaction; TEST(BinderRecordedTransaction, RoundTripEncoding) { + android::String16 interfaceName("SampleInterface"); Parcel d; d.writeInt32(12); d.writeInt64(2); Parcel r; r.writeInt32(99); - auto transaction = RecordedTransaction::fromDetails(1, 42, d, r, 0); + timespec ts = {1232456, 567890}; + + auto transaction = RecordedTransaction::fromDetails(interfaceName, 1, 42, ts, d, r, 0); + EXPECT_TRUE(transaction.has_value()); auto file = std::tmpfile(); auto fd = unique_fd(fcntl(fileno(file), F_DUPFD, 1)); @@ -40,8 +45,11 @@ TEST(BinderRecordedTransaction, RoundTripEncoding) { auto retrievedTransaction = RecordedTransaction::fromFile(fd); + EXPECT_EQ(retrievedTransaction->getInterfaceName(), android::String8(interfaceName)); EXPECT_EQ(retrievedTransaction->getCode(), 1); EXPECT_EQ(retrievedTransaction->getFlags(), 42); + EXPECT_EQ(retrievedTransaction->getTimestamp().tv_sec, ts.tv_sec); + EXPECT_EQ(retrievedTransaction->getTimestamp().tv_nsec, ts.tv_nsec); EXPECT_EQ(retrievedTransaction->getDataParcel().dataSize(), 12); EXPECT_EQ(retrievedTransaction->getReplyParcel().dataSize(), 4); EXPECT_EQ(retrievedTransaction->getReturnedStatus(), 0); @@ -51,3 +59,82 @@ TEST(BinderRecordedTransaction, RoundTripEncoding) { EXPECT_EQ(retrievedTransaction->getDataParcel().readInt64(), 2); EXPECT_EQ(retrievedTransaction->getReplyParcel().readInt32(), 99); } + +TEST(BinderRecordedTransaction, Checksum) { + android::String16 interfaceName("SampleInterface"); + Parcel d; + d.writeInt32(12); + d.writeInt64(2); + Parcel r; + r.writeInt32(99); + timespec ts = {1232456, 567890}; + auto transaction = RecordedTransaction::fromDetails(interfaceName, 1, 42, ts, d, r, 0); + + auto file = std::tmpfile(); + auto fd = unique_fd(fcntl(fileno(file), F_DUPFD, 1)); + + status_t status = transaction->dumpToFile(fd); + ASSERT_EQ(android::NO_ERROR, status); + + lseek(fd.get(), 9, SEEK_SET); + uint32_t badData = 0xffffffff; + write(fd.get(), &badData, sizeof(uint32_t)); + std::rewind(file); + + auto retrievedTransaction = RecordedTransaction::fromFile(fd); + + EXPECT_FALSE(retrievedTransaction.has_value()); +} + +TEST(BinderRecordedTransaction, PayloadsExceedPageBoundaries) { + // File contents are read with mmap. + // This test verifies that transactions are read from portions + // of files that cross page boundaries and don't start at a + // page boundary offset of the fd. + const size_t pageSize = sysconf(_SC_PAGE_SIZE); + const size_t largeDataSize = pageSize + 100; + std::vector<uint8_t> largePayload; + uint8_t filler = 0xaa; + largePayload.insert(largePayload.end(), largeDataSize, filler); + android::String16 interfaceName("SampleInterface"); + Parcel d; + d.writeInt32(12); + d.writeInt64(2); + d.writeByteVector(largePayload); + Parcel r; + r.writeInt32(99); + timespec ts = {1232456, 567890}; + auto transaction = RecordedTransaction::fromDetails(interfaceName, 1, 42, ts, d, r, 0); + + auto file = std::tmpfile(); + auto fd = unique_fd(fcntl(fileno(file), F_DUPFD, 1)); + + // Write to file twice + status_t status = transaction->dumpToFile(fd); + ASSERT_EQ(android::NO_ERROR, status); + status = transaction->dumpToFile(fd); + ASSERT_EQ(android::NO_ERROR, status); + + std::rewind(file); + + for (int i = 0; i < 2; i++) { + auto retrievedTransaction = RecordedTransaction::fromFile(fd); + + EXPECT_EQ(retrievedTransaction->getCode(), 1); + EXPECT_EQ(retrievedTransaction->getFlags(), 42); + EXPECT_EQ(retrievedTransaction->getTimestamp().tv_sec, ts.tv_sec); + EXPECT_EQ(retrievedTransaction->getTimestamp().tv_nsec, ts.tv_nsec); + EXPECT_EQ(retrievedTransaction->getDataParcel().dataSize(), d.dataSize()); + EXPECT_EQ(retrievedTransaction->getReplyParcel().dataSize(), 4); + EXPECT_EQ(retrievedTransaction->getReturnedStatus(), 0); + EXPECT_EQ(retrievedTransaction->getVersion(), 0); + + EXPECT_EQ(retrievedTransaction->getDataParcel().readInt32(), 12); + EXPECT_EQ(retrievedTransaction->getDataParcel().readInt64(), 2); + std::optional<std::vector<uint8_t>> payloadOut; + EXPECT_EQ(retrievedTransaction->getDataParcel().readByteVector(&payloadOut), android::OK); + EXPECT_EQ(payloadOut.value(), largePayload); + + EXPECT_EQ(retrievedTransaction->getReplyParcel().readInt32(), 99); + } +} diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 8afa49b911..36c8d8cd50 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <aidl/IBinderRpcTest.h> #include <android-base/stringprintf.h> #include <chrono> @@ -682,7 +683,7 @@ TEST_P(BinderRpc, SingleDeathRecipientOnShutdown) { proc.expectAlreadyShutdown = true; } -TEST_P(BinderRpc, DeathRecipientFatalWithoutIncoming) { +TEST_P(BinderRpc, DeathRecipientFailsWithoutIncoming) { class MyDeathRec : public IBinder::DeathRecipient { public: void binderDied(const wp<IBinder>& /* who */) override {} @@ -692,8 +693,7 @@ TEST_P(BinderRpc, DeathRecipientFatalWithoutIncoming) { {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 0}); auto dr = sp<MyDeathRec>::make(); - EXPECT_DEATH(proc.rootBinder->linkToDeath(dr, (void*)1, 0), - "Cannot register a DeathRecipient without any incoming connections."); + EXPECT_EQ(INVALID_OPERATION, proc.rootBinder->linkToDeath(dr, (void*)1, 0)); } TEST_P(BinderRpc, UnlinkDeathRecipient) { @@ -1100,15 +1100,6 @@ static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) { return ret; } -static 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); - return versions; -} - INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::Combine(::testing::ValuesIn(testSocketTypes()), ::testing::ValuesIn(RpcSecurityValues()), diff --git a/libs/binder/tests/binderRpcTestCommon.cpp b/libs/binder/tests/binderRpcTestCommon.cpp index 0d9aa952eb..fe9a5a1af7 100644 --- a/libs/binder/tests/binderRpcTestCommon.cpp +++ b/libs/binder/tests/binderRpcTestCommon.cpp @@ -19,6 +19,6 @@ namespace android { std::atomic<int32_t> MyBinderRpcSession::gNum; -sp<IBinder> MyBinderRpcTest::mHeldBinder; +sp<IBinder> MyBinderRpcTestBase::mHeldBinder; } // namespace android diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index 654e16c3be..262d7e4570 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -22,37 +22,42 @@ #include <BnBinderRpcCallback.h> #include <BnBinderRpcSession.h> #include <BnBinderRpcTest.h> -#include <aidl/IBinderRpcTest.h> -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/properties.h> -#include <android/binder_auto_utils.h> -#include <android/binder_libbinder.h> +#include <android-base/stringprintf.h> #include <binder/Binder.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> -#include <binder/ProcessState.h> #include <binder/RpcServer.h> #include <binder/RpcSession.h> #include <binder/RpcThreads.h> -#include <binder/RpcTlsTestUtils.h> -#include <binder/RpcTlsUtils.h> #include <binder/RpcTransport.h> #include <binder/RpcTransportRaw.h> -#include <binder/RpcTransportTls.h> #include <unistd.h> +#include <cinttypes> #include <string> #include <vector> +#ifndef __TRUSTY__ +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/properties.h> +#include <android/binder_auto_utils.h> +#include <android/binder_libbinder.h> +#include <binder/ProcessState.h> +#include <binder/RpcTlsTestUtils.h> +#include <binder/RpcTlsUtils.h> +#include <binder/RpcTransportTls.h> + #include <signal.h> -#include "../BuildFlags.h" -#include "../FdTrigger.h" #include "../OS.h" // for testing UnixBootstrap clients #include "../RpcSocketAddress.h" // for testing preconnected clients -#include "../RpcState.h" // for debugging #include "../vm_sockets.h" // for VMADDR_* +#endif // __TRUSTY__ + +#include "../BuildFlags.h" +#include "../FdTrigger.h" +#include "../RpcState.h" // for debugging #include "utils/Errors.h" namespace android { @@ -65,6 +70,19 @@ static inline std::vector<RpcSecurity> RpcSecurityValues() { return {RpcSecurity::RAW, RpcSecurity::TLS}; } +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); + return versions; +} + +static inline std::string trustyIpcPort(uint32_t serverVersion) { + return base::StringPrintf("com.android.trusty.binderRpcTestService.V%" PRIu32, serverVersion); +} + enum class SocketType { PRECONNECTED, UNIX, @@ -118,6 +136,7 @@ struct BinderRpcOptions { bool allowConnectFailure = false; }; +#ifndef __TRUSTY__ static inline void writeString(android::base::borrowed_fd fd, std::string_view str) { uint64_t length = str.length(); CHECK(android::base::WriteFully(fd, &length, sizeof(length))); @@ -182,6 +201,7 @@ static inline base::unique_fd mockFileDescriptor(std::string contents) { }).detach(); return readFd; } +#endif // __TRUSTY__ // A threadsafe channel where writes block until the value is read. template <typename T> @@ -252,9 +272,12 @@ public: std::vector<std::string> mValues; }; -class MyBinderRpcTest : public BnBinderRpcTest { +// Base class for all concrete implementations of MyBinderRpcTest. +// Sub-classes that want to provide a full implementation should derive +// from this class instead of MyBinderRpcTestDefault below so the compiler +// checks that all methods are implemented. +class MyBinderRpcTestBase : public BnBinderRpcTest { public: - wp<RpcServer> server; int port = 0; Status sendString(const std::string& str) override { @@ -269,18 +292,6 @@ public: *out = port; return Status::ok(); } - Status countBinders(std::vector<int32_t>* out) override { - sp<RpcServer> spServer = server.promote(); - if (spServer == nullptr) { - return Status::fromExceptionCode(Status::EX_NULL_POINTER); - } - out->clear(); - for (auto session : spServer->listSessions()) { - size_t count = session->state()->countBinders(); - out->push_back(count); - } - return Status::ok(); - } Status getNullBinder(sp<IBinder>* out) override { out->clear(); return Status::ok(); @@ -381,62 +392,55 @@ public: return doCallback(callback, oneway, delayed, value); } - Status die(bool cleanup) override { - if (cleanup) { - exit(1); - } else { - _exit(1); - } - } - - Status scheduleShutdown() override { - sp<RpcServer> strongServer = server.promote(); - if (strongServer == nullptr) { +protected: + // Generic version of countBinders that works with both + // RpcServer and RpcServerTrusty + template <typename T> + Status countBindersImpl(const wp<T>& server, std::vector<int32_t>* out) { + sp<T> spServer = server.promote(); + if (spServer == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER); } - RpcMaybeThread([=] { - LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown"); - }).detach(); - return Status::ok(); - } - - Status useKernelBinderCallingId() override { - // this is WRONG! It does not make sense when using RPC binder, and - // because it is SO wrong, and so much code calls this, it should abort! - - if constexpr (kEnableKernelIpc) { - (void)IPCThreadState::self()->getCallingPid(); + out->clear(); + for (auto session : spServer->listSessions()) { + size_t count = session->state()->countBinders(); + out->push_back(count); } return Status::ok(); } +}; - Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override { - out->reset(mockFileDescriptor(content)); - return Status::ok(); +// Default implementation of MyBinderRpcTest that can be used as-is +// or derived from by classes that only want to implement a subset of +// the unimplemented methods +class MyBinderRpcTestDefault : public MyBinderRpcTestBase { +public: + Status countBinders(std::vector<int32_t>* /*out*/) override { + return Status::fromStatusT(UNKNOWN_TRANSACTION); } - Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files, - android::os::ParcelFileDescriptor* out) override { - std::string acc; - for (const auto& file : files) { - std::string result; - CHECK(android::base::ReadFdToString(file.get(), &result)); - acc.append(result); - } - out->reset(mockFileDescriptor(acc)); - return Status::ok(); + Status die(bool /*cleanup*/) override { return Status::fromStatusT(UNKNOWN_TRANSACTION); } + + Status scheduleShutdown() override { return Status::fromStatusT(UNKNOWN_TRANSACTION); } + + Status useKernelBinderCallingId() override { return Status::fromStatusT(UNKNOWN_TRANSACTION); } + + Status echoAsFile(const std::string& /*content*/, + android::os::ParcelFileDescriptor* /*out*/) override { + return Status::fromStatusT(UNKNOWN_TRANSACTION); } - HandoffChannel<android::base::unique_fd> mFdChannel; + Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& /*files*/, + android::os::ParcelFileDescriptor* /*out*/) override { + return Status::fromStatusT(UNKNOWN_TRANSACTION); + } - Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& fd) override { - mFdChannel.write(android::base::unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0))); - return Status::ok(); + Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& /*fd*/) override { + return Status::fromStatusT(UNKNOWN_TRANSACTION); } - Status blockingRecvFd(android::os::ParcelFileDescriptor* fd) override { - fd->reset(mFdChannel.read()); - return Status::ok(); + Status blockingRecvFd(android::os::ParcelFileDescriptor* /*fd*/) override { + return Status::fromStatusT(UNKNOWN_TRANSACTION); } }; diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index cc9726ba6f..714f0636f9 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -18,6 +18,73 @@ using namespace android; +class MyBinderRpcTestAndroid : public MyBinderRpcTestBase { +public: + wp<RpcServer> server; + + Status countBinders(std::vector<int32_t>* out) override { + return countBindersImpl(server, out); + } + + Status die(bool cleanup) override { + if (cleanup) { + exit(1); + } else { + _exit(1); + } + } + + Status scheduleShutdown() override { + sp<RpcServer> strongServer = server.promote(); + if (strongServer == nullptr) { + return Status::fromExceptionCode(Status::EX_NULL_POINTER); + } + RpcMaybeThread([=] { + LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown"); + }).detach(); + return Status::ok(); + } + + Status useKernelBinderCallingId() override { + // this is WRONG! It does not make sense when using RPC binder, and + // because it is SO wrong, and so much code calls this, it should abort! + + if constexpr (kEnableKernelIpc) { + (void)IPCThreadState::self()->getCallingPid(); + } + return Status::ok(); + } + + Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override { + out->reset(mockFileDescriptor(content)); + return Status::ok(); + } + + Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files, + android::os::ParcelFileDescriptor* out) override { + std::string acc; + for (const auto& file : files) { + std::string result; + CHECK(android::base::ReadFdToString(file.get(), &result)); + acc.append(result); + } + out->reset(mockFileDescriptor(acc)); + return Status::ok(); + } + + HandoffChannel<android::base::unique_fd> mFdChannel; + + Status blockingSendFdOneway(const android::os::ParcelFileDescriptor& fd) override { + mFdChannel.write(android::base::unique_fd(fcntl(fd.get(), F_DUPFD_CLOEXEC, 0))); + return Status::ok(); + } + + Status blockingRecvFd(android::os::ParcelFileDescriptor* fd) override { + fd->reset(mFdChannel.read()); + return Status::ok(); + } +}; + int main(int argc, const char* argv[]) { LOG_ALWAYS_FATAL_IF(argc != 3, "Invalid number of arguments: %d", argc); base::unique_fd writeEnd(atoi(argv[1])); @@ -88,7 +155,7 @@ int main(int argc, const char* argv[]) { // sizeof(sa_family_t)==2 in addrlen CHECK_GE(len, sizeof(sa_family_t)); const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr); - sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make(); + sp<MyBinderRpcTestAndroid> service = sp<MyBinderRpcTestAndroid>::make(); switch (addr->sa_family) { case AF_UNIX: // nothing to save diff --git a/libs/binder/tests/binderRpcTestServiceTrusty.cpp b/libs/binder/tests/binderRpcTestServiceTrusty.cpp new file mode 100644 index 0000000000..85573895e9 --- /dev/null +++ b/libs/binder/tests/binderRpcTestServiceTrusty.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. + */ + +#define TLOG_TAG "binderRpcTestService" + +#include <android-base/stringprintf.h> +#include <binder/RpcServerTrusty.h> +#include <inttypes.h> +#include <lib/tipc/tipc.h> +#include <lk/err_ptr.h> +#include <stdio.h> +#include <trusty_log.h> +#include <vector> + +#include "binderRpcTestCommon.h" + +using namespace android; +using android::base::StringPrintf; +using binder::Status; + +static int gConnectionCounter = 0; + +class MyBinderRpcTestTrusty : public MyBinderRpcTestDefault { +public: + wp<RpcServerTrusty> server; + + Status countBinders(std::vector<int32_t>* out) override { + return countBindersImpl(server, out); + } + + Status scheduleShutdown() override { + // TODO: Trusty does not support shutting down the tipc event loop, + // so we just terminate the service app since it is marked + // restart_on_exit + exit(EXIT_SUCCESS); + } + + // TODO(b/242940548): implement echoAsFile and concatFiles +}; + +struct ServerInfo { + std::unique_ptr<std::string> port; + sp<RpcServerTrusty> server; +}; + +int main(void) { + TLOGI("Starting service\n"); + + tipc_hset* hset = tipc_hset_create(); + if (IS_ERR(hset)) { + TLOGE("Failed to create handle set (%d)\n", PTR_ERR(hset)); + return EXIT_FAILURE; + } + + const auto port_acl = RpcServerTrusty::PortAcl{ + .flags = IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT, + }; + + std::vector<ServerInfo> servers; + for (auto serverVersion : testVersions()) { + ServerInfo serverInfo{ + .port = std::make_unique<std::string>(trustyIpcPort(serverVersion)), + }; + TLOGI("Adding service port '%s'\n", serverInfo.port->c_str()); + + // Message size needs to be large enough to cover all messages sent by the + // tests: SendAndGetResultBackBig sends two large strings. + constexpr size_t max_msg_size = 4096; + auto serverOrErr = + RpcServerTrusty::make(hset, serverInfo.port->c_str(), + std::shared_ptr<const RpcServerTrusty::PortAcl>(&port_acl), + max_msg_size); + if (!serverOrErr.ok()) { + TLOGE("Failed to create RpcServer (%d)\n", serverOrErr.error()); + return EXIT_FAILURE; + } + + auto server = std::move(*serverOrErr); + serverInfo.server = server; + serverInfo.server->setProtocolVersion(serverVersion); + serverInfo.server->setPerSessionRootObject([=](const void* /*addrPtr*/, size_t /*len*/) { + auto service = sp<MyBinderRpcTestTrusty>::make(); + // Assign a unique connection identifier to service->port so + // getClientPort returns a unique value per connection + service->port = ++gConnectionCounter; + service->server = server; + return service; + }); + + servers.push_back(std::move(serverInfo)); + } + + return tipc_run_event_loop(hset); +} diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index f960442859..9cd8a829c0 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -327,7 +327,7 @@ TEST_P(BinderRpc, NestedTransactions) { {RpcSession::FileDescriptorTransportMode::UNIX}, }); - auto nastyNester = sp<MyBinderRpcTest>::make(); + auto nastyNester = sp<MyBinderRpcTestDefault>::make(); EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10)); wp<IBinder> weak = nastyNester; diff --git a/libs/binder/tests/binderUtilsHostTest.cpp b/libs/binder/tests/binderUtilsHostTest.cpp index 4330e3e615..25e286ce0c 100644 --- a/libs/binder/tests/binderUtilsHostTest.cpp +++ b/libs/binder/tests/binderUtilsHostTest.cpp @@ -37,17 +37,24 @@ TEST(UtilsHost, ExecuteImmediately) { EXPECT_EQ(result->stdoutStr, "foo\n"); } +template <typename T> +auto millisSince(std::chrono::time_point<T> now) { + auto elapsed = std::chrono::system_clock::now() - now; + return std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); +} + TEST(UtilsHost, ExecuteLongRunning) { - auto now = std::chrono::system_clock::now(); + auto start = std::chrono::system_clock::now(); { - std::vector<std::string> args{"sh", "-c", - "sleep 0.5 && echo -n f && sleep 0.5 && echo oo && sleep 1"}; - auto result = execute(std::move(args), [](const CommandResult& commandResult) { + std::vector<std::string> + args{"sh", "-c", "sleep 0.5 && echo -n f && sleep 0.5 && echo oo && sleep 100"}; + auto result = execute(std::move(args), [&](const CommandResult& commandResult) { + std::cout << millisSince(start) + << "ms: GOT PARTIAL COMMAND RESULT:" << commandResult.stdoutStr << std::endl; return android::base::EndsWith(commandResult.stdoutStr, "\n"); }); - auto elapsed = std::chrono::system_clock::now() - now; - auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); + auto elapsedMs = millisSince(start); EXPECT_GE(elapsedMs, 1000); EXPECT_LT(elapsedMs, 2000); @@ -58,22 +65,21 @@ TEST(UtilsHost, ExecuteLongRunning) { // ~CommandResult() called, child process is killed. // Assert that the second sleep does not finish. - auto elapsed = std::chrono::system_clock::now() - now; - auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); - EXPECT_LT(elapsedMs, 2000); + EXPECT_LT(millisSince(start), 2000); } TEST(UtilsHost, ExecuteLongRunning2) { - auto now = std::chrono::system_clock::now(); + auto start = std::chrono::system_clock::now(); { std::vector<std::string> args{"sh", "-c", - "sleep 2 && echo -n f && sleep 2 && echo oo && sleep 2"}; - auto result = execute(std::move(args), [](const CommandResult& commandResult) { + "sleep 2 && echo -n f && sleep 2 && echo oo && sleep 100"}; + auto result = execute(std::move(args), [&](const CommandResult& commandResult) { + std::cout << millisSince(start) + << "ms: GOT PARTIAL COMMAND RESULT:" << commandResult.stdoutStr << std::endl; return android::base::EndsWith(commandResult.stdoutStr, "\n"); }); - auto elapsed = std::chrono::system_clock::now() - now; - auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); + auto elapsedMs = millisSince(start); EXPECT_GE(elapsedMs, 4000); EXPECT_LT(elapsedMs, 6000); @@ -84,9 +90,7 @@ TEST(UtilsHost, ExecuteLongRunning2) { // ~CommandResult() called, child process is killed. // Assert that the second sleep does not finish. - auto elapsed = std::chrono::system_clock::now() - now; - auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count(); - EXPECT_LT(elapsedMs, 6000); + EXPECT_LT(millisSince(start), 6000); } TEST(UtilsHost, KillWithSigKill) { diff --git a/libs/binder/trusty/binderRpcTest/aidl/rules.mk b/libs/binder/trusty/binderRpcTest/aidl/rules.mk new file mode 100644 index 0000000000..1afd32487a --- /dev/null +++ b/libs/binder/trusty/binderRpcTest/aidl/rules.mk @@ -0,0 +1,30 @@ +# 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_TESTS_DIR := frameworks/native/libs/binder/tests + +MODULE := $(LOCAL_DIR) + +MODULE_AIDLS := \ + $(LIBBINDER_TESTS_DIR)/BinderRpcTestClientInfo.aidl \ + $(LIBBINDER_TESTS_DIR)/BinderRpcTestServerConfig.aidl \ + $(LIBBINDER_TESTS_DIR)/BinderRpcTestServerInfo.aidl \ + $(LIBBINDER_TESTS_DIR)/IBinderRpcCallback.aidl \ + $(LIBBINDER_TESTS_DIR)/IBinderRpcSession.aidl \ + $(LIBBINDER_TESTS_DIR)/IBinderRpcTest.aidl \ + $(LIBBINDER_TESTS_DIR)/ParcelableCertificateData.aidl \ + +include make/aidl.mk diff --git a/libs/binder/trusty/binderRpcTest/service/manifest.json b/libs/binder/trusty/binderRpcTest/service/manifest.json new file mode 100644 index 0000000000..1c4f7ee0d1 --- /dev/null +++ b/libs/binder/trusty/binderRpcTest/service/manifest.json @@ -0,0 +1,10 @@ +{ + "uuid": "87e424e5-69d7-4bbd-8b7c-7e24812cbc94", + "app_name": "binderRpcTestService", + "min_heap": 65536, + "min_stack": 16384, + "mgmt_flags": { + "restart_on_exit": true, + "non_critical_app": true + } +} diff --git a/libs/binder/trusty/binderRpcTest/service/rules.mk b/libs/binder/trusty/binderRpcTest/service/rules.mk new file mode 100644 index 0000000000..5d1a51dca2 --- /dev/null +++ b/libs/binder/trusty/binderRpcTest/service/rules.mk @@ -0,0 +1,33 @@ +# 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_TESTS_DIR := frameworks/native/libs/binder/tests + +MODULE := $(LOCAL_DIR) + +MANIFEST := $(LOCAL_DIR)/manifest.json + +MODULE_SRCS := \ + $(LIBBINDER_TESTS_DIR)/binderRpcTestCommon.cpp \ + $(LIBBINDER_TESTS_DIR)/binderRpcTestServiceTrusty.cpp \ + +MODULE_LIBRARY_DEPS := \ + frameworks/native/libs/binder/trusty \ + frameworks/native/libs/binder/trusty/binderRpcTest/aidl \ + trusty/user/base/lib/libstdc++-trusty \ + trusty/user/base/lib/tipc \ + +include make/trusted_app.mk diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index 7d9dd8c648..6678eb8fec 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -71,6 +71,11 @@ public: } sp<IBinder> getRootObject() { return mRpcServer->getRootObject(); } + /** + * For debugging! + */ + std::vector<sp<RpcSession>> listSessions() { return mRpcServer->listSessions(); } + private: // Both this class and RpcServer have multiple non-copyable fields, // including mPortAcl below which can't be copied because mUuidPtrs diff --git a/libs/binder/trusty/include_mock/lib/tipc/tipc.h b/libs/binder/trusty/include_mock/lib/tipc/tipc.h new file mode 100644 index 0000000000..f295be4980 --- /dev/null +++ b/libs/binder/trusty/include_mock/lib/tipc/tipc.h @@ -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. + */ +#pragma once + +__BEGIN_DECLS + +struct tipc_hset; + +struct tipc_hset* tipc_hset_create(void) { + return nullptr; +} +int tipc_run_event_loop(struct tipc_hset*) { + return 0; +} + +__END_DECLS diff --git a/libs/binder/trusty/include_mock/lk/err_ptr.h b/libs/binder/trusty/include_mock/lk/err_ptr.h new file mode 100644 index 0000000000..ab3fbbacf6 --- /dev/null +++ b/libs/binder/trusty/include_mock/lk/err_ptr.h @@ -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. + */ +#pragma once + +#define IS_ERR(x) (!(x)) +#define PTR_ERR(x) (!!(x)) diff --git a/libs/binder/trusty/include_mock/trusty_ipc.h b/libs/binder/trusty/include_mock/trusty_ipc.h index a2170cea64..43ab84a424 100644 --- a/libs/binder/trusty/include_mock/trusty_ipc.h +++ b/libs/binder/trusty/include_mock/trusty_ipc.h @@ -24,6 +24,9 @@ #define INFINITE_TIME 1 #define IPC_MAX_MSG_HANDLES 8 +#define IPC_PORT_ALLOW_TA_CONNECT 0x1 +#define IPC_PORT_ALLOW_NS_CONNECT 0x2 + #define IPC_HANDLE_POLL_HUP 0x1 #define IPC_HANDLE_POLL_MSG 0x2 #define IPC_HANDLE_POLL_SEND_UNBLOCKED 0x4 diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk index 4e5cd18726..42db29a2ef 100644 --- a/libs/binder/trusty/rules.mk +++ b/libs/binder/trusty/rules.mk @@ -79,6 +79,11 @@ MODULE_EXPORT_COMPILEFLAGS += \ -DBINDER_RPC_SINGLE_THREADED \ -D__ANDROID_VNDK__ \ +# libbinder has some deprecated declarations that we want to produce warnings +# not errors +MODULE_EXPORT_COMPILEFLAGS += \ + -Wno-error=deprecated-declarations \ + MODULE_LIBRARY_DEPS += \ trusty/user/base/lib/libstdc++-trusty \ trusty/user/base/lib/tipc \ diff --git a/libs/binder/trusty/usertests-inc.mk b/libs/binder/trusty/usertests-inc.mk new file mode 100644 index 0000000000..2f5a7f479b --- /dev/null +++ b/libs/binder/trusty/usertests-inc.mk @@ -0,0 +1,17 @@ +# 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. +# + +TRUSTY_USER_TESTS += \ + frameworks/native/libs/binder/trusty/binderRpcTest/service \ diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index b2e8beac43..85a524988d 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -311,6 +311,16 @@ enum AHardwareBuffer_UsageFlags { */ AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26, + /** + * Usage: The buffer is used for front-buffer rendering. When + * front-buffering rendering is specified, different usages may adjust their + * behavior as a result. For example, when used as GPU_COLOR_OUTPUT the buffer + * will behave similar to a single-buffered window. When used with + * COMPOSER_OVERLAY, the system will try to prioritize the buffer receiving + * an overlay plane & avoid caching it in intermediate composition buffers. + */ + AHARDWAREBUFFER_USAGE_FRONT_BUFFER = 1UL << 32, + AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28, AHARDWAREBUFFER_USAGE_VENDOR_1 = 1ULL << 29, AHARDWAREBUFFER_USAGE_VENDOR_2 = 1ULL << 30, diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp index 0a4873c8d3..3fb33b4a12 100644 --- a/libs/ui/tests/colorspace_test.cpp +++ b/libs/ui/tests/colorspace_test.cpp @@ -111,6 +111,7 @@ TEST_F(ColorSpaceTest, TransferFunctions) { EXPECT_NEAR(1.0f, sRGB.getEOTF()(1.0f), 1e-6f); EXPECT_NEAR(1.0f, sRGB.getOETF()(1.0f), 1e-6f); + // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) for (float v = 0.0f; v <= 0.5f; v += 1e-3f) { ASSERT_TRUE(v >= sRGB.getEOTF()(v)); ASSERT_TRUE(v <= sRGB.getOETF()(v)); @@ -118,6 +119,7 @@ TEST_F(ColorSpaceTest, TransferFunctions) { float previousEOTF = std::numeric_limits<float>::lowest(); float previousOETF = std::numeric_limits<float>::lowest(); + // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) for (float v = 0.0f; v <= 1.0f; v += 1e-3f) { ASSERT_TRUE(previousEOTF < sRGB.getEOTF()(v)); previousEOTF = sRGB.getEOTF()(v); @@ -131,6 +133,7 @@ TEST_F(ColorSpaceTest, TransferFunctions) { {0.3127f, 0.3290f} // linear transfer functions ); + // NOLINTNEXTLINE(clang-analyzer-security.FloatLoopCounter,cert-flp30-c) for (float v = 0.0f; v <= 1.0f; v += 1e-3f) { ASSERT_EQ(v, sRGB2.getEOTF()(v)); ASSERT_EQ(v, sRGB2.getOETF()(v)); diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp index 72bd29254d..614a78ecc7 100644 --- a/services/automotive/display/Android.bp +++ b/services/automotive/display/Android.bp @@ -53,4 +53,6 @@ cc_binary { vintf_fragments: [ "manifest_android.frameworks.automotive.display@1.0.xml", ], + + system_ext_specific: true, } diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc index 5c7f344486..ea1077a555 100644 --- a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc +++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc @@ -1,4 +1,4 @@ -service automotive_display /system/bin/android.frameworks.automotive.display@1.0-service +service automotive_display /system_ext/bin/android.frameworks.automotive.display@1.0-service class hal user graphics group automotive_evs diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index c52e96d146..8364ed9d28 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -826,25 +826,24 @@ Error Layer::setPerFrameMetadata(const int32_t supportedPerFrameMetadata, mHdrMetadata.cta8613.maxFrameAverageLightLevel}}); } - Error error = static_cast<Error>( - mComposer.setLayerPerFrameMetadata(mDisplay->getId(), mId, perFrameMetadatas)); + const Error error = static_cast<Error>( + mComposer.setLayerPerFrameMetadata(mDisplay->getId(), mId, perFrameMetadatas)); + if (error != Error::NONE) { + return error; + } + std::vector<Hwc2::PerFrameMetadataBlob> perFrameMetadataBlobs; if (validTypes & HdrMetadata::HDR10PLUS) { if (CC_UNLIKELY(mHdrMetadata.hdr10plus.size() == 0)) { return Error::BAD_PARAMETER; } - std::vector<Hwc2::PerFrameMetadataBlob> perFrameMetadataBlobs; perFrameMetadataBlobs.push_back( {Hwc2::PerFrameMetadataKey::HDR10_PLUS_SEI, mHdrMetadata.hdr10plus}); - Error setMetadataBlobsError = - static_cast<Error>(mComposer.setLayerPerFrameMetadataBlobs(mDisplay->getId(), mId, - perFrameMetadataBlobs)); - if (error == Error::NONE) { - return setMetadataBlobsError; - } } - return error; + + return static_cast<Error>( + mComposer.setLayerPerFrameMetadataBlobs(mDisplay->getId(), mId, perFrameMetadataBlobs)); } Error Layer::setDisplayFrame(const Rect& frame) diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index a2305af554..3611deabce 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -314,12 +314,12 @@ public: virtual void parseArgs(const Vector<String16>& args, std::string& result) = 0; // Sets the max number of display frames that can be stored. Called by SF backdoor. - virtual void setMaxDisplayFrames(uint32_t size); + virtual void setMaxDisplayFrames(uint32_t size) = 0; // Computes the historical fps for the provided set of layer IDs // The fps is compted from the linear timeline of present timestamps for DisplayFrames // containing at least one layer ID. - virtual float computeFps(const std::unordered_set<int32_t>& layerIds); + virtual float computeFps(const std::unordered_set<int32_t>& layerIds) = 0; // Restores the max number of display frames to default. Called by SF backdoor. virtual void reset() = 0; |