Loading libs/binder/RecordedTransaction.cpp +47 −12 Original line number Diff line number Diff line Loading @@ -114,8 +114,8 @@ static_assert(PADDING8(8) == 0); RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept { mData = t.mData; mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); mSentDataOnly.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); mReplyDataOnly.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); } std::optional<RecordedTransaction> RecordedTransaction::fromDetails( Loading @@ -136,12 +136,21 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails( return std::nullopt; } if (t.mSent.setData(dataParcel.data(), dataParcel.dataBufferSize()) != android::NO_ERROR) { if (const auto* kernelFields = dataParcel.maybeKernelFields()) { for (size_t i = 0; i < kernelFields->mObjectsSize; i++) { uint64_t offset = kernelFields->mObjects[i]; t.mData.mSentObjectData.push_back(offset); } } if (t.mSentDataOnly.setData(dataParcel.data(), dataParcel.dataBufferSize()) != android::NO_ERROR) { ALOGE("Failed to set sent parcel data."); return std::nullopt; } if (t.mReply.setData(replyParcel.data(), replyParcel.dataBufferSize()) != android::NO_ERROR) { if (t.mReplyDataOnly.setData(replyParcel.data(), replyParcel.dataBufferSize()) != android::NO_ERROR) { ALOGE("Failed to set reply parcel data."); return std::nullopt; } Loading @@ -154,6 +163,7 @@ enum { DATA_PARCEL_CHUNK = 2, REPLY_PARCEL_CHUNK = 3, INTERFACE_NAME_CHUNK = 4, DATA_PARCEL_OBJECT_CHUNK = 5, END_CHUNK = 0x00ffffff, }; Loading Loading @@ -265,7 +275,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd break; } case DATA_PARCEL_CHUNK: { if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap), if (t.mSentDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap), chunk.dataSize) != android::NO_ERROR) { ALOGE("Failed to set sent parcel data."); return std::nullopt; Loading @@ -273,13 +283,22 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd break; } case REPLY_PARCEL_CHUNK: { if (t.mReply.setData(reinterpret_cast<const unsigned char*>(payloadMap), if (t.mReplyDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap), chunk.dataSize) != android::NO_ERROR) { ALOGE("Failed to set reply parcel data."); return std::nullopt; } break; } case DATA_PARCEL_OBJECT_CHUNK: { const uint64_t* objects = reinterpret_cast<const uint64_t*>(payloadMap); size_t metaDataSize = (chunk.dataSize / sizeof(uint64_t)); ALOGI("Total objects found in saved parcel %zu", metaDataSize); for (size_t index = 0; index < metaDataSize; ++index) { t.mData.mSentObjectData.push_back(objects[index]); } break; } case END_CHUNK: break; default: Loading Loading @@ -343,14 +362,26 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataBufferSize(), mSent.data())) { if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSentDataOnly.dataBufferSize(), mSentDataOnly.data())) { ALOGE("Failed to write sent Parcel to fd %d", fd.get()); return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataBufferSize(), mReply.data())) { if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReplyDataOnly.dataBufferSize(), mReplyDataOnly.data())) { ALOGE("Failed to write reply Parcel to fd %d", fd.get()); return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, DATA_PARCEL_OBJECT_CHUNK, mData.mSentObjectData.size() * sizeof(uint64_t), reinterpret_cast<const uint8_t*>(mData.mSentObjectData.data()))) { ALOGE("Failed to write sent parcel object metadata to fd %d", fd.get()); return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) { ALOGE("Failed to write end chunk to fd %d", fd.get()); return UNKNOWN_ERROR; Loading Loading @@ -384,10 +415,14 @@ uint32_t RecordedTransaction::getVersion() const { return mData.mHeader.version; } const std::vector<uint64_t>& RecordedTransaction::getObjectOffsets() const { return mData.mSentObjectData; } const Parcel& RecordedTransaction::getDataParcel() const { return mSent; return mSentDataOnly; } const Parcel& RecordedTransaction::getReplyParcel() const { return mReply; return mReplyDataOnly; } libs/binder/include/binder/Parcel.h +6 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,9 @@ class String8; class TextOutput; namespace binder { class Status; namespace debug { class RecordedTransaction; } } class Parcel { Loading Loading @@ -1443,6 +1446,9 @@ private: // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference // this size_t getBlobAshmemSize() const; // Needed so that we can save object metadata to the disk friend class android::binder::debug::RecordedTransaction; }; // --------------------------------------------------------------------------- Loading libs/binder/include/binder/RecordedTransaction.h +4 −2 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ public: uint32_t getVersion() const; const Parcel& getDataParcel() const; const Parcel& getReplyParcel() const; const std::vector<uint64_t>& getObjectOffsets() const; private: RecordedTransaction() = default; Loading @@ -75,10 +76,11 @@ private: struct MovableData { // movable TransactionHeader mHeader; std::string mInterfaceName; std::vector<uint64_t> mSentObjectData; /* Object Offsets */ }; MovableData mData; Parcel mSent; Parcel mReply; Parcel mSentDataOnly; Parcel mReplyDataOnly; }; } // namespace binder::debug Loading libs/binder/tests/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -69,10 +69,14 @@ cc_test { cc_test { name: "binderRecordReplayTest", srcs: ["binderRecordReplayTest.cpp"], cflags: [ "-DBINDER_WITH_KERNEL_IPC", ], shared_libs: [ "libbinder", "libcutils", "libutils", "liblog", ], static_libs: [ "binderRecordReplayTestIface-cpp", Loading @@ -96,6 +100,9 @@ aidl_interface { enabled: true, platform_apis: true, }, ndk: { enabled: false, }, }, } Loading libs/binder/tests/IBinderRecordReplayTest.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -69,4 +69,10 @@ interface IBinderRecordReplayTest { void setSingleDataParcelableArray(in SingleDataParcelable[] input); SingleDataParcelable[] getSingleDataParcelableArray(); void setBinder(in IBinder binder); IBinder getBinder(); void setFileDescriptor(in FileDescriptor fd); FileDescriptor getFileDescriptor(); } Loading
libs/binder/RecordedTransaction.cpp +47 −12 Original line number Diff line number Diff line Loading @@ -114,8 +114,8 @@ static_assert(PADDING8(8) == 0); RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept { mData = t.mData; mSent.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); mReply.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); mSentDataOnly.setData(t.getDataParcel().data(), t.getDataParcel().dataSize()); mReplyDataOnly.setData(t.getReplyParcel().data(), t.getReplyParcel().dataSize()); } std::optional<RecordedTransaction> RecordedTransaction::fromDetails( Loading @@ -136,12 +136,21 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails( return std::nullopt; } if (t.mSent.setData(dataParcel.data(), dataParcel.dataBufferSize()) != android::NO_ERROR) { if (const auto* kernelFields = dataParcel.maybeKernelFields()) { for (size_t i = 0; i < kernelFields->mObjectsSize; i++) { uint64_t offset = kernelFields->mObjects[i]; t.mData.mSentObjectData.push_back(offset); } } if (t.mSentDataOnly.setData(dataParcel.data(), dataParcel.dataBufferSize()) != android::NO_ERROR) { ALOGE("Failed to set sent parcel data."); return std::nullopt; } if (t.mReply.setData(replyParcel.data(), replyParcel.dataBufferSize()) != android::NO_ERROR) { if (t.mReplyDataOnly.setData(replyParcel.data(), replyParcel.dataBufferSize()) != android::NO_ERROR) { ALOGE("Failed to set reply parcel data."); return std::nullopt; } Loading @@ -154,6 +163,7 @@ enum { DATA_PARCEL_CHUNK = 2, REPLY_PARCEL_CHUNK = 3, INTERFACE_NAME_CHUNK = 4, DATA_PARCEL_OBJECT_CHUNK = 5, END_CHUNK = 0x00ffffff, }; Loading Loading @@ -265,7 +275,7 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd break; } case DATA_PARCEL_CHUNK: { if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap), if (t.mSentDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap), chunk.dataSize) != android::NO_ERROR) { ALOGE("Failed to set sent parcel data."); return std::nullopt; Loading @@ -273,13 +283,22 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd break; } case REPLY_PARCEL_CHUNK: { if (t.mReply.setData(reinterpret_cast<const unsigned char*>(payloadMap), if (t.mReplyDataOnly.setData(reinterpret_cast<const unsigned char*>(payloadMap), chunk.dataSize) != android::NO_ERROR) { ALOGE("Failed to set reply parcel data."); return std::nullopt; } break; } case DATA_PARCEL_OBJECT_CHUNK: { const uint64_t* objects = reinterpret_cast<const uint64_t*>(payloadMap); size_t metaDataSize = (chunk.dataSize / sizeof(uint64_t)); ALOGI("Total objects found in saved parcel %zu", metaDataSize); for (size_t index = 0; index < metaDataSize; ++index) { t.mData.mSentObjectData.push_back(objects[index]); } break; } case END_CHUNK: break; default: Loading Loading @@ -343,14 +362,26 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const { return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataBufferSize(), mSent.data())) { if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSentDataOnly.dataBufferSize(), mSentDataOnly.data())) { ALOGE("Failed to write sent Parcel to fd %d", fd.get()); return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataBufferSize(), mReply.data())) { if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReplyDataOnly.dataBufferSize(), mReplyDataOnly.data())) { ALOGE("Failed to write reply Parcel to fd %d", fd.get()); return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, DATA_PARCEL_OBJECT_CHUNK, mData.mSentObjectData.size() * sizeof(uint64_t), reinterpret_cast<const uint8_t*>(mData.mSentObjectData.data()))) { ALOGE("Failed to write sent parcel object metadata to fd %d", fd.get()); return UNKNOWN_ERROR; } if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) { ALOGE("Failed to write end chunk to fd %d", fd.get()); return UNKNOWN_ERROR; Loading Loading @@ -384,10 +415,14 @@ uint32_t RecordedTransaction::getVersion() const { return mData.mHeader.version; } const std::vector<uint64_t>& RecordedTransaction::getObjectOffsets() const { return mData.mSentObjectData; } const Parcel& RecordedTransaction::getDataParcel() const { return mSent; return mSentDataOnly; } const Parcel& RecordedTransaction::getReplyParcel() const { return mReply; return mReplyDataOnly; }
libs/binder/include/binder/Parcel.h +6 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,9 @@ class String8; class TextOutput; namespace binder { class Status; namespace debug { class RecordedTransaction; } } class Parcel { Loading Loading @@ -1443,6 +1446,9 @@ private: // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference // this size_t getBlobAshmemSize() const; // Needed so that we can save object metadata to the disk friend class android::binder::debug::RecordedTransaction; }; // --------------------------------------------------------------------------- Loading
libs/binder/include/binder/RecordedTransaction.h +4 −2 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ public: uint32_t getVersion() const; const Parcel& getDataParcel() const; const Parcel& getReplyParcel() const; const std::vector<uint64_t>& getObjectOffsets() const; private: RecordedTransaction() = default; Loading @@ -75,10 +76,11 @@ private: struct MovableData { // movable TransactionHeader mHeader; std::string mInterfaceName; std::vector<uint64_t> mSentObjectData; /* Object Offsets */ }; MovableData mData; Parcel mSent; Parcel mReply; Parcel mSentDataOnly; Parcel mReplyDataOnly; }; } // namespace binder::debug Loading
libs/binder/tests/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -69,10 +69,14 @@ cc_test { cc_test { name: "binderRecordReplayTest", srcs: ["binderRecordReplayTest.cpp"], cflags: [ "-DBINDER_WITH_KERNEL_IPC", ], shared_libs: [ "libbinder", "libcutils", "libutils", "liblog", ], static_libs: [ "binderRecordReplayTestIface-cpp", Loading @@ -96,6 +100,9 @@ aidl_interface { enabled: true, platform_apis: true, }, ndk: { enabled: false, }, }, } Loading
libs/binder/tests/IBinderRecordReplayTest.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -69,4 +69,10 @@ interface IBinderRecordReplayTest { void setSingleDataParcelableArray(in SingleDataParcelable[] input); SingleDataParcelable[] getSingleDataParcelableArray(); void setBinder(in IBinder binder); IBinder getBinder(); void setFileDescriptor(in FileDescriptor fd); FileDescriptor getFileDescriptor(); }