Merge "binderUtilsHostTest: more debuggable"
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index a80da4e..12a7cff 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -8,6 +8,7 @@
socket dumpstate stream 0660 shell log
disabled
oneshot
+ capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID KILL NET_ADMIN NET_RAW SETGID SETUID SYS_PTRACE SYS_RESOURCE BLOCK_SUSPEND SYSLOG
# dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
# it is finished.
@@ -16,9 +17,11 @@
class main
disabled
oneshot
+ capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID KILL NET_ADMIN NET_RAW SETGID SETUID SYS_PTRACE SYS_RESOURCE BLOCK_SUSPEND SYSLOG
# bugreportd starts dumpstate binder service and makes it wait for a listener to connect.
service bugreportd /system/bin/dumpstate -w
class main
disabled
oneshot
+ capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID KILL NET_ADMIN NET_RAW SETGID SETUID SYS_PTRACE SYS_RESOURCE BLOCK_SUSPEND SYSLOG
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 28369d6..e70a98d 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -517,6 +517,7 @@
visibility: [
":__subpackages__",
"//packages/modules/Virtualization:__subpackages__",
+ "//device/google/cuttlefish/shared/minidroid:__subpackages__",
],
}
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 5e725a9..da5affb 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -407,8 +407,10 @@
AutoMutex lock(e->mLock);
if (mRecordingOn) {
Parcel emptyReply;
+ timespec ts;
+ timespec_get(&ts, TIME_UTC);
auto transaction =
- android::binder::debug::RecordedTransaction::fromDetails(code, flags, data,
+ android::binder::debug::RecordedTransaction::fromDetails(code, flags, ts, data,
reply ? *reply
: emptyReply,
err);
diff --git a/libs/binder/BinderRecordReplay.cpp b/libs/binder/BinderRecordReplay.cpp
index 90c02a8..8ba18a8 100644
--- a/libs/binder/BinderRecordReplay.cpp
+++ b/libs/binder/BinderRecordReplay.cpp
@@ -16,10 +16,12 @@
#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;
@@ -30,42 +32,100 @@
static_assert(PADDING8(7) == 1);
static_assert(PADDING8(8) == 0);
-// Transactions are sequentially recorded to the file descriptor in the following format:
+// Transactions are sequentially recorded to a file descriptor.
//
-// RecordedTransaction.TransactionHeader (32 bytes)
-// Sent Parcel data (getDataSize() bytes)
-// padding (enough bytes to align the reply Parcel data to 8 bytes)
-// Reply Parcel data (getReplySize() bytes)
-// padding (enough bytes to align the next header to 8 bytes)
-// [repeats with next transaction]
+// An individual RecordedTransaction is written with the following format:
//
-// Warning: This format is non-stable
+// 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.getDataSize(),
- t.getReplySize(), t.getReturnedStatus(), t.getVersion()};
- mSent.setData(t.getDataParcel().data(), t.getDataSize());
- mReply.setData(t.getReplyParcel().data(), t.getReplySize());
+ mHeader = t.mHeader;
+ 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,
+ timespec timestamp,
const Parcel& dataParcel,
const Parcel& replyParcel,
status_t err) {
RecordedTransaction t;
t.mHeader = {code,
flags,
- static_cast<uint64_t>(dataParcel.dataSize()),
- static_cast<uint64_t>(replyParcel.dataSize()),
static_cast<int32_t>(err),
- dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0)};
+ 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};
- if (t.mSent.setData(dataParcel.data(), t.getDataSize()) != android::NO_ERROR) {
+ 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(), t.getReplySize()) != android::NO_ERROR) {
+ if (t.mReply.setData(replyParcel.data(), replyParcel.dataSize()) != android::NO_ERROR) {
LOG(INFO) << "Failed to set reply parcel data.";
return std::nullopt;
}
@@ -73,80 +133,155 @@
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;
- if (!android::base::ReadFully(fd, &t.mHeader, sizeof(mHeader))) {
- LOG(INFO) << "Failed to read transactionHeader from fd " << fd.get();
- return std::nullopt;
- }
- if (t.getVersion() != 0) {
- LOG(INFO) << "File corrupted: transaction version is not 0.";
- return std::nullopt;
- }
+ ChunkDescriptor chunk;
- std::vector<uint8_t> bytes;
- bytes.resize(t.getDataSize());
- if (!android::base::ReadFully(fd, bytes.data(), t.getDataSize())) {
- LOG(INFO) << "Failed to read sent parcel data from fd " << fd.get();
- return std::nullopt;
- }
- if (t.mSent.setData(bytes.data(), t.getDataSize()) != android::NO_ERROR) {
- LOG(INFO) << "Failed to set sent parcel data.";
- return std::nullopt;
- }
-
- uint8_t padding[7];
- if (!android::base::ReadFully(fd, padding, PADDING8(t.getDataSize()))) {
- LOG(INFO) << "Failed to read sent parcel padding from fd " << fd.get();
- return std::nullopt;
- }
- if (std::any_of(padding, padding + 7, [](uint8_t i) { return i != 0; })) {
- LOG(INFO) << "File corrupted: padding isn't 0.";
- return std::nullopt;
- }
-
- bytes.resize(t.getReplySize());
- if (!android::base::ReadFully(fd, bytes.data(), t.getReplySize())) {
- LOG(INFO) << "Failed to read reply parcel data from fd " << fd.get();
- return std::nullopt;
- }
- if (t.mReply.setData(bytes.data(), t.getReplySize()) != android::NO_ERROR) {
- LOG(INFO) << "Failed to set reply parcel data.";
- return std::nullopt;
- }
-
- if (!android::base::ReadFully(fd, padding, PADDING8(t.getReplySize()))) {
- LOG(INFO) << "Failed to read parcel padding from fd " << fd.get();
- return std::nullopt;
- }
- if (std::any_of(padding, padding + 7, [](uint8_t i) { return i != 0; })) {
- LOG(INFO) << "File corrupted: padding isn't 0.";
- return std::nullopt;
- }
+ 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;
+ }
+ lseek(fd.get(), chunk.padding, SEEK_CUR);
+ 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 (!android::base::WriteFully(fd, &mHeader, sizeof(mHeader))) {
+ 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 (!android::base::WriteFully(fd, mSent.data(), getDataSize())) {
- LOG(INFO) << "Failed to write sent parcel data to fd " << fd.get();
+ 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;
}
- const uint8_t zeros[7] = {0};
- if (!android::base::WriteFully(fd, zeros, PADDING8(getDataSize()))) {
- LOG(INFO) << "Failed to write sent parcel padding to fd " << fd.get();
+ 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 (!android::base::WriteFully(fd, mReply.data(), getReplySize())) {
- LOG(INFO) << "Failed to write reply parcel data to fd " << fd.get();
- return UNKNOWN_ERROR;
- }
- if (!android::base::WriteFully(fd, zeros, PADDING8(getReplySize()))) {
- LOG(INFO) << "Failed to write reply parcel padding to fd " << fd.get();
+ 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;
@@ -160,18 +295,16 @@
return mHeader.flags;
}
-uint64_t RecordedTransaction::getDataSize() const {
- return mHeader.dataSize;
-}
-
-uint64_t RecordedTransaction::getReplySize() const {
- return mHeader.replySize;
-}
-
int32_t RecordedTransaction::getReturnedStatus() const {
return mHeader.statusReturned;
}
+timespec RecordedTransaction::getTimestamp() const {
+ time_t sec = mHeader.timestampSeconds;
+ int32_t nsec = mHeader.timestampNanoseconds;
+ return (timespec){.tv_sec = sec, .tv_nsec = nsec};
+}
+
uint32_t RecordedTransaction::getVersion() const {
return mHeader.version;
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 6d64e1e..da58251 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1221,6 +1221,10 @@
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/include/binder/BinderRecordReplay.h b/libs/binder/include/binder/BinderRecordReplay.h
index 25ed5e5..ff983f0 100644
--- a/libs/binder/include/binder/BinderRecordReplay.h
+++ b/libs/binder/include/binder/BinderRecordReplay.h
@@ -34,17 +34,16 @@
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);
+ 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;
uint32_t getCode() const;
uint32_t getFlags() const;
- uint64_t getDataSize() const;
- uint64_t getReplySize() const;
int32_t getReturnedStatus() const;
+ timespec getTimestamp() const;
uint32_t getVersion() const;
const Parcel& getDataParcel() const;
const Parcel& getReplyParcel() const;
@@ -52,15 +51,19 @@
private:
RecordedTransaction() = default;
+ android::status_t writeChunk(const android::base::borrowed_fd, uint32_t chunkType,
+ size_t byteCount, const uint8_t* data) const;
+
#pragma clang diagnostic push
#pragma clang diagnostic error "-Wpadded"
struct TransactionHeader {
uint32_t code = 0;
uint32_t flags = 0;
- uint64_t dataSize = 0;
- uint64_t replySize = 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) == 32);
@@ -69,10 +72,6 @@
TransactionHeader mHeader;
Parcel mSent;
Parcel mReply;
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-private-field"
- uint8_t mReserved[40];
-#pragma clang diagnostic pop
};
} // namespace binder::debug
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 2af512e..c78f870 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -198,7 +198,10 @@
{
const sp<IServiceManager> sm = defaultServiceManager();
if (sm != nullptr) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
*outService = interface_cast<INTERFACE>(sm->getService(name));
+#pragma clang diagnostic pop // getService deprecation
if ((*outService) != nullptr) return NO_ERROR;
}
return NAME_NOT_FOUND;
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 78dae4b..e7943dd 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -112,6 +112,13 @@
LOG(ERROR) << "Failed to get fd for the socket:" << name;
return nullptr;
}
+ // Control socket fds are inherited from init, so they don't have O_CLOEXEC set.
+ // But we don't want any child processes to inherit the socket we are running
+ // the server on, so attempt to set the flag now.
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
+ LOG(WARNING) << "Failed to set CLOEXEC on control socket with name " << name
+ << " error: " << errno;
+ }
if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) {
LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name
<< " error: " << statusToString(status).c_str();
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 2a00736..e3ead11 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,19 @@
#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 +111,12 @@
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 +143,21 @@
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> ||
+ std::is_same_v<os::ParcelFileDescriptor, _U> ||
+ std::is_same_v<os::ParcelableHolder, _U>
#endif
- ,
- std::true_type>
+ ,
+ std::true_type>
_test(int);
template <typename _U>
static std::false_type _test(...);
@@ -155,6 +166,11 @@
enum { value = decltype(_test<_T>(0))::value };
};
+template <typename _T>
+struct TypeDependentFalse {
+ enum { value = false };
+};
+
} // namespace details
template <typename _T>
@@ -214,11 +230,27 @@
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/tests/Android.bp b/libs/binder/tests/Android.bp
index a999d59..5db3187 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -100,6 +100,7 @@
"binderBinderUnitTest.cpp",
"binderStatusUnitTest.cpp",
"binderMemoryHeapBaseUnitTest.cpp",
+ "binderRecordedTransactionTest.cpp",
],
shared_libs: [
"libbinder",
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index 6a6e008..bc40864 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -180,7 +180,11 @@
mallocs++;
// Happens to be SM package length. We could switch to forking
// and registering our own service if it became an issue.
+#if defined(__LP64__)
EXPECT_EQ(bytes, 78);
+#else
+ EXPECT_EQ(bytes, 70);
+#endif
});
a_binder->getInterfaceDescriptor();
diff --git a/libs/binder/tests/binderRecordedTransactionTest.cpp b/libs/binder/tests/binderRecordedTransactionTest.cpp
new file mode 100644
index 0000000..2ece315
--- /dev/null
+++ b/libs/binder/tests/binderRecordedTransactionTest.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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 <binder/BinderRecordReplay.h>
+#include <gtest/gtest.h>
+
+using android::Parcel;
+using android::status_t;
+using android::base::unique_fd;
+using android::binder::debug::RecordedTransaction;
+
+TEST(BinderRecordedTransaction, RoundTripEncoding) {
+ Parcel d;
+ d.writeInt32(12);
+ d.writeInt64(2);
+ Parcel r;
+ r.writeInt32(99);
+ timespec ts = {1232456, 567890};
+ auto transaction = RecordedTransaction::fromDetails(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);
+
+ std::rewind(file);
+
+ 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(), 12);
+ 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);
+ EXPECT_EQ(retrievedTransaction->getReplyParcel().readInt32(), 99);
+}
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 53e7de4..08eb27a 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -199,5 +199,25 @@
binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel());
FUZZ_LOG() << "status: " << status;
},
+ [](const NdkParcelAdapter& p, FuzzedDataProvider& provider) {
+ FUZZ_LOG() << "about to marshal AParcel";
+ size_t start = provider.ConsumeIntegral<size_t>();
+ // limit 1MB to avoid OOM issues
+ size_t len = provider.ConsumeIntegralInRange<size_t>(0, 1000000);
+ uint8_t buffer[len];
+ binder_status_t status = AParcel_marshal(p.aParcel(), buffer, start, len);
+ FUZZ_LOG() << "status: " << status;
+ },
+ [](const NdkParcelAdapter& /*p*/, FuzzedDataProvider& provider) {
+ FUZZ_LOG() << "about to unmarshal AParcel";
+ size_t len = provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes());
+ std::vector<uint8_t> parcelData = provider.ConsumeBytes<uint8_t>(len);
+ const uint8_t* buffer = parcelData.data();
+ const size_t bufferLen = parcelData.size();
+ NdkParcelAdapter adapter;
+ binder_status_t status = AParcel_unmarshal(adapter.aParcel(), buffer, bufferLen);
+ FUZZ_LOG() << "status: " << status;
+ },
+
};
// clang-format on
diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp
index 0a4873c..3fb33b4 100644
--- a/libs/ui/tests/colorspace_test.cpp
+++ b/libs/ui/tests/colorspace_test.cpp
@@ -111,6 +111,7 @@
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 @@
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 @@
{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));