/* * 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 #include #include using android::Parcel; using android::status_t; using android::binder::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(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)); status_t status = transaction->dumpToFile(fd); ASSERT_EQ(android::NO_ERROR, status); std::rewind(file); auto retrievedTransaction = RecordedTransaction::fromFile(fd); EXPECT_EQ(retrievedTransaction->getInterfaceName(), android::String8(interfaceName).c_str()); 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); } 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(interfaceName, 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); lseek(fd.get(), 9, SEEK_SET); uint32_t badData = 0xffffffff; write(fd.get(), &badData, sizeof(uint32_t)); std::rewind(file); auto retrievedTransaction = RecordedTransaction::fromFile(fd); EXPECT_FALSE(retrievedTransaction.has_value()); } TEST(BinderRecordedTransaction, PayloadsExceedPageBoundaries) { // File contents are read with mmap. // This test verifies that transactions are read from portions // of files that cross page boundaries and don't start at a // page boundary offset of the fd. const size_t pageSize = sysconf(_SC_PAGE_SIZE); const size_t largeDataSize = pageSize + 100; std::vector largePayload; uint8_t filler = 0xaa; largePayload.insert(largePayload.end(), largeDataSize, filler); android::String16 interfaceName("SampleInterface"); Parcel d; d.writeInt32(12); d.writeInt64(2); d.writeByteVector(largePayload); Parcel r; r.writeInt32(99); timespec ts = {1232456, 567890}; 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)); // Write to file twice status_t status = transaction->dumpToFile(fd); ASSERT_EQ(android::NO_ERROR, status); status = transaction->dumpToFile(fd); ASSERT_EQ(android::NO_ERROR, status); std::rewind(file); for (int i = 0; i < 2; i++) { 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(), d.dataSize()); 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); std::optional> payloadOut; EXPECT_EQ(retrievedTransaction->getDataParcel().readByteVector(&payloadOut), android::OK); EXPECT_EQ(payloadOut.value(), largePayload); EXPECT_EQ(retrievedTransaction->getReplyParcel().readInt32(), 99); } }