diff --git a/interfaces/innerkits/ipc_core/include/message_parcel.h b/interfaces/innerkits/ipc_core/include/message_parcel.h index 7a941afc028cf8167e9de7d8a3b3d6b129270aef..0f3302e7a32645e704aed744373b304cf1330aed 100644 --- a/interfaces/innerkits/ipc_core/include/message_parcel.h +++ b/interfaces/innerkits/ipc_core/include/message_parcel.h @@ -50,6 +50,7 @@ public: { needCloseFd_ = true; }; + bool Append(MessageParcel &data); private: #ifndef CONFIG_IPC_SINGLE diff --git a/ipc/native/src/core/source/message_parcel.cpp b/ipc/native/src/core/source/message_parcel.cpp index fa6f2dd8575136fa3033ca57fbf34a931e021700..bdce65d30daae5039132a1e3e723f8bf6f92e5d3 100644 --- a/ipc/native/src/core/source/message_parcel.cpp +++ b/ipc/native/src/core/source/message_parcel.cpp @@ -37,12 +37,44 @@ namespace OHOS { #define TITLE __PRETTY_FUNCTION__ #endif +#ifdef CONFIG_IPC_SINGLE +using namespace IPC_SINGLE; +#endif + static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "MessageParcel" }; #define DBINDER_LOGE(fmt, args...) \ (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) #define DBINDER_LOGI(fmt, args...) \ (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args) +void AcquireObject(flat_binder_object *flat, const void *cookie) +{ + switch (flat->hdr.type) { + case BINDER_TYPE_BINDER: + if (flat->binder) { + reinterpret_cast(flat->cookie)->IncStrongRef(cookie); + } + break; + case BINDER_TYPE_HANDLE: { + IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent(); + IRemoteObject *remoteObject = nullptr; + if (current != nullptr) { + remoteObject = current->QueryObject(current->MakeHandleDescriptor(flat->handle)); + } + if (remoteObject != nullptr) { + remoteObject->IncStrongRef(cookie); + } + break; + } + case BINDER_TYPE_FD: + flat->handle = dup(flat->handle); + break; + default: + DBINDER_LOGE("binder object type is invalid."); + break; + } +} + MessageParcel::MessageParcel() : Parcel(), writeRawDataFd_(-1), @@ -422,4 +454,44 @@ sptr MessageParcel::ReadAshmem() } return new (std::nothrow) Ashmem(fd, size); } + +bool MessageParcel::Append(MessageParcel &data) +{ + size_t dataSize = data.GetDataSize(); + if (dataSize == 0) { + DBINDER_LOGE("no data to append"); + return true; + } + uintptr_t dataPtr = data.GetData(); + size_t writeCursorOld = this->GetWritePosition(); + if (!WriteBuffer(reinterpret_cast(dataPtr), dataSize)) { + DBINDER_LOGE("failed to append data with writebuffer."); + return false; + } + size_t objectSize = data.GetOffsetsSize(); + if (objectSize == 0) { + return true; + } + binder_size_t objectOffsets = data.GetObjectOffsets(); + auto *newObjectOffsets = reinterpret_cast(objectOffsets); + for (size_t index = 0; index < objectSize; index++) { + if (EnsureObjectsCapacity()) { + size_t offset = writeCursorOld + newObjectOffsets[index]; + if (!WriteObjectOffset(offset)) { + DBINDER_LOGE("failed to write object offset"); + return false; + } + flat_binder_object *flat = reinterpret_cast(this->GetData() + offset); + if (flat == nullptr) { + DBINDER_LOGE("flat binder object is nullptr"); + return false; + } + AcquireObject(flat, this); + } else { + DBINDER_LOGE("Failed to ensure parcel capacity"); + return false; + } + } + return true; +} } // namespace OHOS diff --git a/ipc/test/auxiliary/native/include/test_service.h b/ipc/test/auxiliary/native/include/test_service.h index fe519981b2896aea26f1c083710dcbe6d836c7ed..0e738abe82e53549ff33ad8fe4387fc39b478d68 100644 --- a/ipc/test/auxiliary/native/include/test_service.h +++ b/ipc/test/auxiliary/native/include/test_service.h @@ -46,6 +46,9 @@ public: void TestAsyncDumpService() override; int TestNestingSend(int sendCode, int &replyCode) override; int TestAccessTokenID(int32_t ftoken_expected) override; + int TestMessageParcelAppend(MessageParcel &dst, MessageParcel &src) override; + int TestMessageParcelAppendWithIpc(MessageParcel &dst, MessageParcel &src, + MessageParcel &reply, bool withObject) override; private: int testFd_; static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestService" }; diff --git a/ipc/test/auxiliary/native/include/test_service_skeleton.h b/ipc/test/auxiliary/native/include/test_service_skeleton.h index d56341165e64940712eef2c918575b01dc61a727..6ff1a2abdf0a802f3f9096fe38d8c880670b9089 100644 --- a/ipc/test/auxiliary/native/include/test_service_skeleton.h +++ b/ipc/test/auxiliary/native/include/test_service_skeleton.h @@ -47,6 +47,8 @@ public: TRANS_ID_ASYNC_DUMP_SERVICE = 16, TRANS_ID_NESTING_SEND = 17, TRANS_ID_ACCESS_TOKENID = 18, + TRANS_MESSAGE_PARCEL_ADDPED = 19, + TRANS_MESSAGE_PARCEL_ADDPED_WITH_OBJECT = 20, }; public: virtual int TestSyncTransaction(int data, int &reply, int delayTime = 0) = 0; @@ -67,6 +69,9 @@ public: virtual void TestAsyncDumpService() = 0; virtual int TestNestingSend(int sendCode, int &replyCode) = 0; virtual int TestAccessTokenID(int32_t ftoken_expected) = 0; + virtual int TestMessageParcelAppend(MessageParcel &dst, MessageParcel &src) = 0; + virtual int TestMessageParcelAppendWithIpc(MessageParcel &dst, MessageParcel &src, + MessageParcel &reply, bool withObject) = 0; public: DECLARE_INTERFACE_DESCRIPTOR(u"test.ipc.ITestService"); }; @@ -105,6 +110,9 @@ public: void TestAsyncDumpService() override; int TestNestingSend(int sendCode, int &replyCode) override; int TestAccessTokenID(int32_t ftoken_expected) override; + int TestMessageParcelAppend(MessageParcel &dst, MessageParcel &src) override; + int TestMessageParcelAppendWithIpc(MessageParcel &dst, MessageParcel &src, + MessageParcel &reply, bool withObject) override; private: static inline BrokerDelegator delegator_; static constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_ID_IPC, "TestServiceProxy" }; diff --git a/ipc/test/auxiliary/native/src/test_service.cpp b/ipc/test/auxiliary/native/src/test_service.cpp index 144b300de2fc537f4107bdd9ea1d3439e6f04d1f..3fd8df9e48cc204c360180e62f7123092ac20baa 100644 --- a/ipc/test/auxiliary/native/src/test_service.cpp +++ b/ipc/test/auxiliary/native/src/test_service.cpp @@ -192,6 +192,23 @@ int TestService::TestAccessTokenID(int32_t ftoken_expected) return 0; } +int TestService::TestMessageParcelAppend(MessageParcel &dst, MessageParcel &src) +{ + (void)dst; + (void)src; + return 0; +} + +int TestService::TestMessageParcelAppendWithIpc(MessageParcel &dst, MessageParcel &src, + MessageParcel &reply, bool withObject) +{ + (void)dst; + (void)src; + (void)reply; + (void)withObject; + return 0; +} + int TestService::TestFlushAsyncCalls(int count, int length) { return 0; diff --git a/ipc/test/auxiliary/native/src/test_service_skeleton.cpp b/ipc/test/auxiliary/native/src/test_service_skeleton.cpp index 0b042569798d41e991a241960dba5b69f605cb4a..b750cbde3ac05b7761b5f31c4104bb740cd2f9a4 100644 --- a/ipc/test/auxiliary/native/src/test_service_skeleton.cpp +++ b/ipc/test/auxiliary/native/src/test_service_skeleton.cpp @@ -426,6 +426,34 @@ int TestServiceProxy::TestAccessTokenID(int32_t ftoken_expected) return 0; } +int TestServiceProxy::TestMessageParcelAppend(MessageParcel &dst, MessageParcel &src) +{ + bool res = dst.Append(src); + if (!res) { + ZLOGE(LABEL, "message parcel append without ipc failed"); + return -1; + } + return 0; +} + +int TestServiceProxy::TestMessageParcelAppendWithIpc(MessageParcel &dst, MessageParcel &src, + MessageParcel &reply, bool withObject) +{ + bool res = dst.Append(src); + if (!res) { + ZLOGE(LABEL, "message parcel append with ipc failed"); + return -1; + } + MessageOption option; + uint32_t code = TRANS_MESSAGE_PARCEL_ADDPED; + if (withObject) { + code = TRANS_MESSAGE_PARCEL_ADDPED_WITH_OBJECT; + } + int ret = Remote()->SendRequest(code, dst, reply, option); + ZLOGE(LABEL, "TestMessageParcelAppend with ipc sendrequest ret = %{public}d", ret); + return ret; +} + int TestServiceProxy::TestFlushAsyncCalls(int count, int length) { int ret; @@ -646,6 +674,20 @@ int TestServiceStub::OnRemoteRequest(uint32_t code, reply.WriteInt32(ftoken); break; } + case TRANS_MESSAGE_PARCEL_ADDPED: { + reply.WriteInt32(data.ReadInt32()); + reply.WriteInt32(data.ReadInt32()); + reply.WriteString(data.ReadString()); + break; + } + case TRANS_MESSAGE_PARCEL_ADDPED_WITH_OBJECT: { + reply.WriteInt32(data.ReadInt32()); + reply.WriteInt32(data.ReadInt32()); + reply.WriteString(data.ReadString()); + reply.WriteRemoteObject(data.ReadRemoteObject()); + reply.WriteFileDescriptor(data.ReadFileDescriptor()); + break; + } default: ret = IPCObjectStub::OnRemoteRequest(code, data, reply, option); break; diff --git a/ipc/test/moduletest/native/common/ipc_core_module_test.cpp b/ipc/test/moduletest/native/common/ipc_core_module_test.cpp index 2f23c48d00e23394c1e8ae0536d5ed88782bfc37..d2930bd87a48d3ad67433a8e9add0466d069bccb 100644 --- a/ipc/test/moduletest/native/common/ipc_core_module_test.cpp +++ b/ipc/test/moduletest/native/common/ipc_core_module_test.cpp @@ -27,6 +27,9 @@ #include "system_ability_definition.h" #include "ipc_object_proxy.h" +#include "directory_ex.h" +#include "foo_service.h" + #include "log_tags.h" using namespace testing::ext; @@ -738,3 +741,145 @@ HWTEST_F(IPCNativeFrameworkTest, function_test_024, TestSize.Level1) thread->join(); } } + +/** + * @tc.name: function_test_025 + * @tc.desc: Test messageparcel append in same process + * @tc.type: FUNC + * @tc.require: AR000H0FUK + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_025, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + MessageParcel dstParcel, srcParcel; + int ret = testService->TestMessageParcelAppend(dstParcel, srcParcel); + EXPECT_EQ(ret, 0); + + const int32_t num = 5767168; + const std::string strwrite1 = + "test for write string padded**********************************************************##################"; + dstParcel.WriteInt32(num); + dstParcel.WriteString(strwrite1); + srcParcel.WriteInt32(num); + srcParcel.WriteString(strwrite1); + sptr fooCallback = new FooStub(); + srcParcel.WriteRemoteObject(fooCallback->AsObject()); + ret = testService->TestMessageParcelAppend(dstParcel, srcParcel); + EXPECT_EQ(ret, 0); + EXPECT_EQ(num, dstParcel.ReadInt32()); + EXPECT_EQ(strwrite1, dstParcel.ReadString()); + EXPECT_EQ(num, dstParcel.ReadInt32()); + EXPECT_EQ(strwrite1, dstParcel.ReadString()); + res = dstParcel.ReadRemoteObject(); + ASSERT_TRUE(res); + + ret = testService->TestMessageParcelAppend(srcParcel, dstParcel); + EXPECT_EQ(ret, 0); + EXPECT_EQ(num, srcParcel.ReadInt32()); + EXPECT_EQ(strwrite1, srcParcel.ReadString()); + res = srcParcel.ReadRemoteObject(); + ASSERT_TRUE(res); + EXPECT_EQ(num, srcParcel.ReadInt32()); + EXPECT_EQ(strwrite1, srcParcel.ReadString()); +} + +/** + * @tc.name: function_test_026 + * @tc.desc: Test messageparcel append with ipc + * @tc.type: FUNC + * @tc.require: AR000H0FUK + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_026, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + MessageParcel dstParcel, srcParcel, reply; + const int32_t num = 5767168; + dstParcel.WriteInt32(num); + srcParcel.WriteInt32(num); + const std::string strwrite1 = + "test for write string padded**********************************************************##################"; + srcParcel.WriteString(strwrite1); + int ret = testService->TestMessageParcelAppendWithIpc(dstParcel, srcParcel, reply, false); + EXPECT_EQ(ret, 0); + EXPECT_EQ(num, reply.ReadInt32()); + EXPECT_EQ(num, reply.ReadInt32()); + EXPECT_EQ(strwrite1, reply.ReadString()); +} + +/** + * @tc.name: function_test_027 + * @tc.desc: Test messageparcel append with ipc + * @tc.type: FUNC + * @tc.require: AR000H0FUK + */ +HWTEST_F(IPCNativeFrameworkTest, function_test_027, TestSize.Level1) +{ + IPCTestHelper helper; + bool res = helper.StartTestApp(IPCTestHelper::IPC_TEST_SERVER); + ASSERT_TRUE(res); + + auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_TRUE(saMgr != nullptr); + + sptr object = saMgr->GetSystemAbility(IPC_TEST_SERVICE); + ASSERT_TRUE(object != nullptr); + + sptr testService = iface_cast(object); + ASSERT_TRUE(testService != nullptr); + + MessageParcel dstParcel, srcParcel, reply; + const int32_t num = 5767168; + dstParcel.WriteInt32(num); + srcParcel.WriteInt32(num); + const std::string strwrite1 = + "test for write string padded**********************************************************##################"; + srcParcel.WriteString(strwrite1); + sptr fooCallback = new FooStub(); + srcParcel.WriteRemoteObject(fooCallback->AsObject()); + + const std::string dirpath = "/data/test_dir"; + res = ForceCreateDirectory(dirpath); + ASSERT_TRUE(res); + string filename = dirpath + "/test.txt"; + int fd = open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + EXPECT_GT(fd, 0); + res = srcParcel.WriteFileDescriptor(fd); // write fd + ASSERT_TRUE(res); + + int ret = testService->TestMessageParcelAppendWithIpc(dstParcel, srcParcel, reply, true); + EXPECT_EQ(ret, 0); + EXPECT_EQ(num, reply.ReadInt32()); + EXPECT_EQ(num, reply.ReadInt32()); + EXPECT_EQ(strwrite1, reply.ReadString()); + res = reply.ReadRemoteObject(); + ASSERT_TRUE(res); + res = reply.ReadFileDescriptor(); + ASSERT_TRUE(res); + + RemoveFile(filename); + ForceRemoveDirectory(dirpath); +} \ No newline at end of file