Loading libs/binder/Binder.cpp +3 −5 Original line number Diff line number Diff line Loading @@ -409,11 +409,9 @@ status_t BBinder::transact( 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; Loading libs/binder/BinderRecordReplay.cpp +43 −21 Original line number Diff line number Diff line Loading @@ -106,18 +106,16 @@ static_assert(PADDING8(8) == 0); // 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, t.mData.mHeader = {code, flags, static_cast<int32_t>(err), dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0), Loading @@ -125,6 +123,14 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails(uint32_t cod 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; Loading @@ -142,6 +148,7 @@ enum { HEADER_CHUNK = 1, DATA_PARCEL_CHUNK = 2, REPLY_PARCEL_CHUNK = 3, INTERFACE_NAME_CHUNK = 4, END_CHUNK = 0x00ffffff, }; Loading Loading @@ -220,7 +227,11 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd << 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: { Loading Loading @@ -291,10 +302,17 @@ android::status_t RecordedTransaction::writeChunk(borrowed_fd fd, uint32_t chunk 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; Loading @@ -310,26 +328,30 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { 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 { Loading libs/binder/include/binder/BinderRecordReplay.h +8 −2 Original line number Diff line number Diff line Loading @@ -33,13 +33,15 @@ 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, 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; Loading Loading @@ -69,7 +71,11 @@ private: static_assert(sizeof(TransactionHeader) == 32); static_assert(sizeof(TransactionHeader) % 8 == 0); struct MovableData { // movable TransactionHeader mHeader; String8 mInterfaceName; }; MovableData mData; Parcel mSent; Parcel mReply; }; Loading libs/binder/tests/binderRecordedTransactionTest.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -24,13 +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); 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)); Loading @@ -42,6 +45,7 @@ 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); Loading @@ -57,13 +61,14 @@ TEST(BinderRecordedTransaction, RoundTripEncoding) { } 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)); Loading Loading @@ -91,6 +96,7 @@ TEST(BinderRecordedTransaction, PayloadsExceedPageBoundaries) { 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); Loading @@ -98,7 +104,7 @@ TEST(BinderRecordedTransaction, PayloadsExceedPageBoundaries) { 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)); Loading Loading
libs/binder/Binder.cpp +3 −5 Original line number Diff line number Diff line Loading @@ -409,11 +409,9 @@ status_t BBinder::transact( 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; Loading
libs/binder/BinderRecordReplay.cpp +43 −21 Original line number Diff line number Diff line Loading @@ -106,18 +106,16 @@ static_assert(PADDING8(8) == 0); // 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, t.mData.mHeader = {code, flags, static_cast<int32_t>(err), dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0), Loading @@ -125,6 +123,14 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails(uint32_t cod 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; Loading @@ -142,6 +148,7 @@ enum { HEADER_CHUNK = 1, DATA_PARCEL_CHUNK = 2, REPLY_PARCEL_CHUNK = 3, INTERFACE_NAME_CHUNK = 4, END_CHUNK = 0x00ffffff, }; Loading Loading @@ -220,7 +227,11 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd << 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: { Loading Loading @@ -291,10 +302,17 @@ android::status_t RecordedTransaction::writeChunk(borrowed_fd fd, uint32_t chunk 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; Loading @@ -310,26 +328,30 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { 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 { Loading
libs/binder/include/binder/BinderRecordReplay.h +8 −2 Original line number Diff line number Diff line Loading @@ -33,13 +33,15 @@ 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, 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; Loading Loading @@ -69,7 +71,11 @@ private: static_assert(sizeof(TransactionHeader) == 32); static_assert(sizeof(TransactionHeader) % 8 == 0); struct MovableData { // movable TransactionHeader mHeader; String8 mInterfaceName; }; MovableData mData; Parcel mSent; Parcel mReply; }; Loading
libs/binder/tests/binderRecordedTransactionTest.cpp +9 −3 Original line number Diff line number Diff line Loading @@ -24,13 +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); 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)); Loading @@ -42,6 +45,7 @@ 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); Loading @@ -57,13 +61,14 @@ TEST(BinderRecordedTransaction, RoundTripEncoding) { } 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)); Loading Loading @@ -91,6 +96,7 @@ TEST(BinderRecordedTransaction, PayloadsExceedPageBoundaries) { 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); Loading @@ -98,7 +104,7 @@ TEST(BinderRecordedTransaction, PayloadsExceedPageBoundaries) { 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)); Loading