Add interfaceDescriptor to RecordedTransaction
This change adds a binder's interfaceDescriptor to RecordedTransaction.
While most Parcels self-identify with an interface descriptor, that is
not required. By adding the name of the interface that generated the
transaction, a RecordedTransaction and its Parcels can be more easily
decoded.
Test: `atest binderUnitTest`
Change-Id: I052640bf26ee3fa67a74a388ee4de930a684e2f4
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index da5affb..5fa8bfa 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -409,11 +409,9 @@
Parcel emptyReply;
timespec ts;
timespec_get(&ts, TIME_UTC);
- auto transaction =
- android::binder::debug::RecordedTransaction::fromDetails(code, flags, ts, data,
- reply ? *reply
- : emptyReply,
- err);
+ 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
index 58bb106..389c49e 100644
--- a/libs/binder/BinderRecordReplay.cpp
+++ b/libs/binder/BinderRecordReplay.cpp
@@ -106,24 +106,30 @@
// End Chunk may therefore produce an empty, meaningless RecordedTransaction.
RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept {
- mHeader = t.mHeader;
+ mData = t.mData;
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) {
+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.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.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.";
@@ -142,6 +148,7 @@
HEADER_CHUNK = 1,
DATA_PARCEL_CHUNK = 2,
REPLY_PARCEL_CHUNK = 3,
+ INTERFACE_NAME_CHUNK = 4,
END_CHUNK = 0x00ffffff,
};
@@ -220,7 +227,11 @@
<< sizeof(TransactionHeader) << ".";
return std::nullopt;
}
- t.mHeader = *reinterpret_cast<TransactionHeader*>(payloadMap);
+ 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: {
@@ -291,10 +302,17 @@
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))) {
+ 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;
@@ -310,26 +328,30 @@
return NO_ERROR;
}
+const android::String8& RecordedTransaction::getInterfaceName() const {
+ return mData.mInterfaceName;
+}
+
uint32_t RecordedTransaction::getCode() const {
- return mHeader.code;
+ return mData.mHeader.code;
}
uint32_t RecordedTransaction::getFlags() const {
- return mHeader.flags;
+ return mData.mHeader.flags;
}
int32_t RecordedTransaction::getReturnedStatus() const {
- return mHeader.statusReturned;
+ return mData.mHeader.statusReturned;
}
timespec RecordedTransaction::getTimestamp() const {
- time_t sec = mHeader.timestampSeconds;
- int32_t nsec = mHeader.timestampNanoseconds;
+ 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 mHeader.version;
+ return mData.mHeader.version;
}
const Parcel& RecordedTransaction::getDataParcel() const {
diff --git a/libs/binder/include/binder/BinderRecordReplay.h b/libs/binder/include/binder/BinderRecordReplay.h
index ff983f0..9602c9f 100644
--- a/libs/binder/include/binder/BinderRecordReplay.h
+++ b/libs/binder/include/binder/BinderRecordReplay.h
@@ -33,13 +33,15 @@
// 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,
+ 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;
@@ -69,7 +71,11 @@
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/tests/binderRecordedTransactionTest.cpp b/libs/binder/tests/binderRecordedTransactionTest.cpp
index 67553fc..d900e86 100644
--- a/libs/binder/tests/binderRecordedTransactionTest.cpp
+++ b/libs/binder/tests/binderRecordedTransactionTest.cpp
@@ -24,13 +24,16 @@
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);
timespec ts = {1232456, 567890};
- auto transaction = RecordedTransaction::fromDetails(1, 42, ts, d, r, 0);
+
+ 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));
@@ -42,6 +45,7 @@
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);
@@ -57,13 +61,14 @@
}
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(1, 42, ts, d, r, 0);
+ 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));
@@ -91,6 +96,7 @@
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);
@@ -98,7 +104,7 @@
Parcel r;
r.writeInt32(99);
timespec ts = {1232456, 567890};
- auto transaction = RecordedTransaction::fromDetails(1, 42, ts, d, r, 0);
+ 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));