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));