1 /*
2 * Copyright (C) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef OHOS_IPC_DBINDER_BASE_INVOKER_PROCESS_H
17 #define OHOS_IPC_DBINDER_BASE_INVOKER_PROCESS_H
18
19 #include "dbinder_base_invoker_define.h"
20 #include "hitrace_invoker.h"
21
22 namespace OHOS {
23
24 template <class T>
SendReplyWithSeqNum(uint64_t seqNum,MessageParcel & reply,uint32_t flags,int32_t result)25 void DBinderBaseInvoker<T>::SendReplyWithSeqNum(uint64_t seqNum, MessageParcel &reply, uint32_t flags, int32_t result)
26 {
27 if (!(flags & MessageOption::TF_ASYNC)) {
28 SetSeqNum(seqNum);
29 SendReply(reply, 0, result);
30 SetSeqNum(0);
31 }
32 }
33
StartLoopFailSendReply(const char * buffer,uint32_t size,int32_t result)34 template <class T> void DBinderBaseInvoker<T>::StartLoopFailSendReply(const char *buffer, uint32_t size, int32_t result)
35 {
36 MessageParcel reply;
37 const dbinder_transaction_data *tr = reinterpret_cast<const dbinder_transaction_data *>(buffer);
38 SendReplyWithSeqNum(tr->seqNumber, reply, tr->flags, result);
39 }
40
41 template <class T>
TargetStubSendRequest(dbinder_transaction_data * tr,int32_t listenFd,uint64_t seqNum,MessageParcel & data,MessageParcel & reply)42 int DBinderBaseInvoker<T>::TargetStubSendRequest(dbinder_transaction_data *tr, int32_t listenFd, uint64_t seqNum,
43 MessageParcel &data, MessageParcel &reply)
44 {
45 IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent();
46 if (current == nullptr) {
47 ZLOGE(LOG_LABEL, "IPCProcessSkeleton is nullptr");
48 DfxReportFailEvent(DbinderErrorCode::RPC_DRIVER, RADAR_IPC_PROCESS_SKELETON_NULL, __FUNCTION__);
49 return RPC_BASE_INVOKER_CURRENT_NULL_ERR;
50 }
51
52 int error = ERR_NONE;
53 std::lock_guard<std::mutex> lockGuard(objectMutex_);
54 auto *stub = current->QueryStubByIndex(tr->cookie);
55 if (stub == nullptr) {
56 ZLOGE(LOG_LABEL, "stubIndex is invalid, listenFd:%{public}d seq:%{public}" PRIu64,
57 listenFd, seqNum);
58 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_STUB_INVALID, __FUNCTION__);
59 return RPC_BASE_INVOKER_STUBINDEX_ERR;
60 }
61
62 MessageOption option;
63 option.SetFlags(tr->flags);
64 auto *stubObject = reinterpret_cast<IPCObjectStub *>(stub);
65 // cannot use stub any more after SendRequest because this cmd may be
66 // dbinder dec ref and thus stub will be destroyed
67 error = stubObject->SendRequest(tr->code, data, reply, option);
68 if (error != ERR_NONE) {
69 ZLOGW(LOG_LABEL, "stub sendrequest failed, cmd:%{public}u error:%{public}d "
70 "listenFd:%{public}d seq:%{public}" PRIu64, tr->code, error, listenFd, seqNum);
71 // can not return;
72 }
73
74 if (data.GetRawData() != nullptr) {
75 ZLOGW(LOG_LABEL, "delete raw data in process skeleton, listenFd:%{public}d seq:%{public}" PRIu64,
76 listenFd, seqNum);
77 current->DetachRawData(listenFd);
78 }
79 return error;
80 }
81
ProcessTransaction(dbinder_transaction_data * tr,int32_t listenFd)82 template <class T> void DBinderBaseInvoker<T>::ProcessTransaction(dbinder_transaction_data *tr, int32_t listenFd)
83 {
84 uint64_t senderSeqNumber = tr->seqNumber;
85 MessageParcel data, reply;
86 if (!IRemoteObjectTranslateWhenRcv(tr, data, listenFd)) {
87 ZLOGE(LOG_LABEL, "translate object failed, listenFd:%{public}d seq:%{public}" PRIu64,
88 listenFd, senderSeqNumber);
89 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_TRANSLATE_FAIL, __FUNCTION__);
90 SendReplyWithSeqNum(senderSeqNumber, reply, tr->flags, RPC_BASE_INVOKER_TRANSLATE_ERR);
91 return;
92 }
93
94 uint32_t oldStatus = GetStatus();
95 DBinderCallerInfo oldCallerInfo;
96 GetCallerInfo(oldCallerInfo);
97 int ret = CheckAndSetCallerInfo(listenFd, tr->cookie);
98 if (ret != ERR_NONE) {
99 ZLOGE(LOG_LABEL, "check and set caller info failed, cmd:%{public}u listenFd:%{public}d", tr->code, listenFd);
100 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_CHECK_AND_SET_CALLER_FAIL, __FUNCTION__);
101 SendReplyWithSeqNum(senderSeqNumber, reply, tr->flags, ret);
102 return;
103 }
104
105 auto allocator = new (std::nothrow) DBinderSendAllocator();
106 if (allocator == nullptr) {
107 ZLOGE(LOG_LABEL, "DBinderSendAllocator failed, listenFd:%{public}d", listenFd);
108 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_SEND_ALLOCATOR_FAIL, __FUNCTION__);
109 SendReplyWithSeqNum(senderSeqNumber, reply, tr->flags, ERR_ALLOC_MEMORY);
110 SetCallerInfo(oldCallerInfo);
111 return;
112 }
113 if (!data.SetAllocator(allocator)) {
114 delete allocator;
115 ZLOGE(LOG_LABEL, "SetAllocator failed, listenFd:%{public}d", listenFd);
116 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_SET_ALLOCATOR_FAIL, __FUNCTION__);
117 SendReplyWithSeqNum(senderSeqNumber, reply, tr->flags, ERR_UNKNOWN_REASON);
118 SetCallerInfo(oldCallerInfo);
119 return;
120 }
121 data.ParseFrom(reinterpret_cast<uintptr_t>(tr->buffer), tr->buffer_size);
122 if (!(tr->flags & MessageOption::TF_STATUS_CODE) && tr->offsets_size > 0) {
123 data.InjectOffsets(reinterpret_cast<binder_uintptr_t>(reinterpret_cast<char *>(tr->buffer) + tr->offsets),
124 tr->offsets_size / sizeof(binder_size_t));
125 }
126
127 uint32_t &newflags = const_cast<uint32_t &>(tr->flags);
128 int isServerTraced = HitraceInvoker::TraceServerReceieve(tr->cookie, tr->code, data, newflags);
129 SetStatus(IRemoteInvoker::ACTIVE_INVOKER);
130 int error = TargetStubSendRequest(tr, listenFd, senderSeqNumber, data, reply);
131 HitraceInvoker::TraceServerSend(tr->cookie, tr->code, isServerTraced, newflags);
132 SendReplyWithSeqNum(senderSeqNumber, reply, tr->flags, error);
133 SetStatus(oldStatus);
134 SetCallerInfo(oldCallerInfo);
135 }
136
ProcessReply(dbinder_transaction_data * tr,int32_t listenFd)137 template <class T> void DBinderBaseInvoker<T>::ProcessReply(dbinder_transaction_data *tr, int32_t listenFd)
138 {
139 IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent();
140 if (current == nullptr) {
141 ZLOGE(LOG_LABEL, "IPCProcessSkeleton is nullptr, can not wakeup thread");
142 DfxReportFailEvent(DbinderErrorCode::RPC_DRIVER, RADAR_IPC_PROCESS_SKELETON_NULL, __FUNCTION__);
143 return;
144 }
145
146 std::shared_ptr<ThreadMessageInfo> messageInfo = current->QueryThreadBySeqNumber(tr->seqNumber);
147 int32_t retryCount = 0;
148 while (messageInfo == nullptr) {
149 ZLOGW(LOG_LABEL, "query thread for reply failed, seqNum:%{public}llu, listenFd:%{public}d, retry:%{public}d",
150 tr->seqNumber, listenFd, retryCount++);
151 if (retryCount == REPLY_RETRY_COUNT) {
152 ZLOGE(LOG_LABEL, "query thread for reply failed, no thread waiting reply message");
153 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_SEQ_MESSAGE_NULL, __FUNCTION__);
154 return; // messageInfo is null, no thread need to wakeup
155 }
156 std::this_thread::sleep_for(std::chrono::milliseconds(REPLY_RETRY_WAIT_MS));
157 messageInfo = current->QueryThreadBySeqNumber(tr->seqNumber);
158 }
159
160 /* tr->sizeOfSelf > sizeof(dbinder_transaction_data) is checked in CheckTransactionData */
161 messageInfo->buffer = new (std::nothrow) unsigned char[tr->sizeOfSelf - sizeof(dbinder_transaction_data)];
162 if (messageInfo->buffer == nullptr) {
163 ZLOGE(LOG_LABEL, "some thread is waiting for reply message, but no memory"
164 ", seqNumber:%{public}llu listenFd:%{public}d", tr->seqNumber, listenFd);
165 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_SEQ_MESSAGE_BUFFER_NULL, __FUNCTION__);
166 /* wake up sender thread */
167 current->WakeUpThreadBySeqNumber(tr->seqNumber, listenFd);
168 return;
169 }
170 /* copy receive message to sender thread */
171 int memcpyResult = memcpy_s(messageInfo->buffer, tr->sizeOfSelf - sizeof(dbinder_transaction_data), tr->buffer,
172 tr->sizeOfSelf - sizeof(dbinder_transaction_data));
173 if (memcpyResult != 0) {
174 ZLOGE(LOG_LABEL, "memcpy_s failed, error:%{public}d seqNumber:%{public}llu listenFd:%{public}d",
175 memcpyResult, tr->seqNumber, listenFd);
176 DfxReportFailListenEvent(DbinderErrorCode::RPC_DRIVER, listenFd, RADAR_ERR_MEMCPY_DATA, __FUNCTION__);
177 delete[](unsigned char *) messageInfo->buffer;
178 messageInfo->buffer = nullptr;
179 /* wake up sender thread even no memssage */
180 current->WakeUpThreadBySeqNumber(tr->seqNumber, listenFd);
181 return;
182 }
183
184 messageInfo->flags = tr->flags;
185 messageInfo->bufferSize = tr->buffer_size;
186 messageInfo->offsetsSize = tr->offsets_size;
187 messageInfo->offsets = tr->offsets;
188 messageInfo->socketId = static_cast<uint32_t>(listenFd);
189
190 /* wake up sender thread */
191 current->WakeUpThreadBySeqNumber(tr->seqNumber, listenFd);
192 }
193
194 template <class T>
ProcessRawData(std::shared_ptr<T> sessionObject,MessageParcel & data,uint64_t seqNum)195 bool DBinderBaseInvoker<T>::ProcessRawData(std::shared_ptr<T> sessionObject, MessageParcel &data, uint64_t seqNum)
196 {
197 if (data.GetRawData() == nullptr || data.GetRawDataSize() == 0) {
198 return true; // do nothing, return true
199 }
200
201 std::shared_ptr<dbinder_transaction_data> transData = nullptr;
202 size_t totalSize = sizeof(dbinder_transaction_data) + data.GetRawDataSize();
203 transData.reset(reinterpret_cast<dbinder_transaction_data *>(::operator new(totalSize)));
204 if (transData == nullptr) {
205 ZLOGE(LOG_LABEL, "fail to create raw buffer with length:%{public}zu", totalSize);
206 return false;
207 }
208
209 ConstructTransData(data, *transData, totalSize, seqNum, BC_SEND_RAWDATA, 0, 0);
210 int result = memcpy_s(reinterpret_cast<char *>(transData.get()) + sizeof(dbinder_transaction_data),
211 totalSize - sizeof(dbinder_transaction_data), data.GetRawData(), data.GetRawDataSize());
212 if (result != 0) {
213 ZLOGE(LOG_LABEL, "memcpy data fail, size:%{public}zu", data.GetRawDataSize());
214 return false;
215 }
216 result = OnSendRawData(sessionObject, transData.get(), totalSize);
217 if (result != 0) {
218 ZLOGE(LOG_LABEL, "fail to send raw data");
219 return false;
220 }
221 return true;
222 }
223
224 template <class T>
ProcessNormalData(std::shared_ptr<T> sessionObject,MessageParcel & data,int32_t handle,int32_t socketId,uint64_t seqNum,int cmd,__u32 code,__u32 flags,int status)225 std::shared_ptr<dbinder_transaction_data> DBinderBaseInvoker<T>::ProcessNormalData(std::shared_ptr<T> sessionObject,
226 MessageParcel &data, int32_t handle, int32_t socketId, uint64_t seqNum, int cmd, __u32 code, __u32 flags,
227 int status)
228 {
229 uint32_t sendSize = ((data.GetDataSize() > 0) ? data.GetDataSize() : sizeof(binder_size_t)) +
230 sizeof(struct dbinder_transaction_data) + data.GetOffsetsSize() * T::GetFlatSessionLen() +
231 data.GetOffsetsSize() * sizeof(binder_size_t);
232
233 std::shared_ptr<dbinder_transaction_data> transData = nullptr;
234 transData.reset(reinterpret_cast<dbinder_transaction_data *>(::operator new(sendSize)));
235 if (transData == nullptr) {
236 ZLOGE(LOG_LABEL, "new buffer failed of length:%{public}u", sendSize);
237 return nullptr;
238 }
239 ConstructTransData(data, *transData, sendSize, seqNum, cmd, code, flags);
240 transData->cookie = (handle == 0) ? 0 : sessionObject->GetStubIndex();
241 if (MoveMessageParcel2TransData(data, sessionObject, transData, socketId, status) != true) {
242 ZLOGE(LOG_LABEL, "move parcel to transData failed, handle:%{public}d socketId:%{public}d", handle, socketId);
243 return nullptr;
244 }
245 return transData;
246 }
247
248 template <class T>
MakeThreadProcessInfo(int32_t socketId,const char * inBuffer,uint32_t size)249 std::shared_ptr<ThreadProcessInfo> DBinderBaseInvoker<T>::MakeThreadProcessInfo(int32_t socketId, const char *inBuffer,
250 uint32_t size)
251 {
252 if (inBuffer == nullptr || size < sizeof(dbinder_transaction_data) || size > SOCKET_MAX_BUFF_SIZE) {
253 ZLOGE(LOG_LABEL, "buffer is null or size:%{public}u invalid, socketId:%{public}d", size, socketId);
254 return nullptr;
255 }
256
257 std::shared_ptr<ThreadProcessInfo> processInfo(new ThreadProcessInfo, [](ThreadProcessInfo *ptr) {
258 if (ptr != nullptr) {
259 delete ptr;
260 ptr = nullptr;
261 }
262 });
263 if (processInfo == nullptr) {
264 ZLOGE(LOG_LABEL, "make ThreadProcessInfo fail, socketId:%{public}d", socketId);
265 return nullptr;
266 }
267 std::shared_ptr<char> buffer(new (std::nothrow) char[size]);
268 if (buffer == nullptr) {
269 ZLOGE(LOG_LABEL, "new buffer failed of length:%{public}u socketId:%{public}d", size, socketId);
270 return nullptr;
271 }
272
273 int memcpyResult = memcpy_s(buffer.get(), size, inBuffer, size);
274 if (memcpyResult != 0) {
275 ZLOGE(LOG_LABEL, "memcpy_s failed , size:%{public}u socketId:%{public}d", size, socketId);
276 return nullptr;
277 }
278
279 processInfo->listenFd = socketId;
280 processInfo->packageSize = size;
281 processInfo->buffer = buffer;
282 return processInfo;
283 }
284
285 template <class T>
RemoveDBinderPtrData(std::shared_ptr<dbinder_transaction_data> tr,uint32_t & cutCount)286 bool DBinderBaseInvoker<T>::RemoveDBinderPtrData(std::shared_ptr<dbinder_transaction_data> tr, uint32_t &cutCount)
287 {
288 size_t i = 0;
289 size_t objCount = tr->offsets_size / sizeof(binder_size_t);
290 while (i < objCount) {
291 binder_size_t *offsets = reinterpret_cast<binder_size_t *>(tr->buffer + tr->buffer_size);
292 auto obj = reinterpret_cast<binder_object_header *>(tr->buffer + offsets[i]);
293 if (obj->type == BINDER_TYPE_PTR) {
294 ZLOGI(LOG_LABEL, "ptr object offset:%{public}llu", offsets[i]);
295 // record deleted offset
296 binder_size_t delOffset = offsets[i];
297 // update these offsets that following the deleted offset
298 for (size_t j = i; (j + 1) < objCount; j++) {
299 offsets[j] = offsets[j + 1] - sizeof(binder_buffer_object);
300 }
301 // update total offsets size
302 tr->offsets_size -= sizeof(binder_size_t);
303
304 // remove ptr space in the buffer
305 size_t removeSize = tr->buffer_size + tr->offsets_size - delOffset - sizeof(binder_buffer_object);
306 errno_t ret = memmove_s(tr->buffer + delOffset, removeSize,
307 tr->buffer + delOffset + sizeof(binder_buffer_object), removeSize);
308 if (ret != EOK) {
309 ZLOGE(LOG_LABEL, "memmove fail, %{public}d", ret);
310 return false;
311 }
312 // update buffer size
313 tr->buffer_size -= sizeof(binder_buffer_object);
314 // update offsets
315 tr->offsets = tr->buffer_size;
316
317 // clear the disused buffer space
318 size_t delSize = sizeof(binder_size_t) + sizeof(binder_buffer_object) + T::GetFlatSessionLen();
319 memset_s(tr->buffer + tr->buffer_size + tr->offsets_size, delSize, 0, delSize);
320 // update sizeofSelf
321 tr->sizeOfSelf -= delSize;
322 ++cutCount;
323 }
324 ++i;
325 }
326 return true;
327 }
328
329 template <class T>
OverrideMessageParcelData(std::shared_ptr<dbinder_transaction_data> tr,MessageParcel & data)330 void DBinderBaseInvoker<T>::OverrideMessageParcelData(std::shared_ptr<dbinder_transaction_data> tr, MessageParcel &data)
331 {
332 // override data(MessageParcel)
333 data.FlushBuffer();
334 data.WriteBuffer(reinterpret_cast<const void *>(tr->buffer), tr->buffer_size);
335 // set offsets
336 size_t objCount = tr->offsets_size / sizeof(binder_size_t);
337 if (objCount > 0) {
338 data.InjectOffsets(reinterpret_cast<binder_uintptr_t>(tr->buffer + tr->offsets), objCount);
339 }
340 }
341
342 template <class T>
PrintDBinderTransaction(const char * funcName,const char * titleName,const dbinder_transaction_data * tr)343 void DBinderBaseInvoker<T>::PrintDBinderTransaction(const char *funcName, const char *titleName,
344 const dbinder_transaction_data *tr)
345 {
346 if (funcName == nullptr || titleName == nullptr || tr == nullptr) {
347 ZLOGE(LOG_LABEL, "invalid param");
348 return;
349 }
350 ZLOGI(LOG_LABEL, "[%{public}s %{public}s]: sizeOfSelf:%{public}u, magic:%{public}u, version:%{public}u, "
351 "cmd:%{public}d, code:%{public}u, flags:%{public}u, cookie:%{public}llu, seqNumber:%{public}llu, "
352 "buffer_size:%{public}llu, offsets_size:%{public}llu, offsets:%{public}llu, "
353 "sizeof(dbinder_transaction_data):%{public}zu",
354 funcName, titleName, tr->sizeOfSelf, tr->magic, tr->version, tr->cmd, tr->code, tr->flags, tr->cookie,
355 tr->seqNumber, tr->buffer_size, tr->offsets_size, tr->offsets, sizeof(dbinder_transaction_data));
356 }
357
358 template <class T>
PrintBuffer(const char * funcName,const char * titleName,const uint8_t * data,size_t length)359 void DBinderBaseInvoker<T>::PrintBuffer(const char *funcName, const char *titleName, const uint8_t *data,
360 size_t length)
361 {
362 std::string format;
363 size_t idx = 0;
364 while (idx < length) {
365 format += std::to_string(data[idx]) + ',';
366 ++idx;
367 }
368 ZLOGI(LOG_LABEL, "[%{public}s %{public}s]: length:%{public}zu, content:%{public}s",
369 funcName, titleName, length, format.c_str());
370 }
371
372 template <class T>
MoveMessageParcel2TransData(MessageParcel & data,std::shared_ptr<T> sessionObject,std::shared_ptr<dbinder_transaction_data> transData,int32_t socketId,int status)373 bool DBinderBaseInvoker<T>::MoveMessageParcel2TransData(MessageParcel &data, std::shared_ptr<T> sessionObject,
374 std::shared_ptr<dbinder_transaction_data> transData, int32_t socketId, int status)
375 {
376 if (data.GetDataSize() > 0) {
377 /* Send this parcel's data through the socket. */
378 transData->buffer_size = data.GetDataSize();
379 uint32_t useSize = transData->sizeOfSelf - sizeof(dbinder_transaction_data);
380 int memcpyResult =
381 memcpy_s(transData->buffer, useSize, reinterpret_cast<void *>(data.GetData()), transData->buffer_size);
382 if (data.GetOffsetsSize() > 0) {
383 memcpyResult += memcpy_s(transData->buffer + transData->buffer_size, useSize - transData->buffer_size,
384 reinterpret_cast<void *>(data.GetObjectOffsets()), data.GetOffsetsSize() * sizeof(binder_size_t));
385 }
386 if (memcpyResult != 0) {
387 ZLOGE(LOG_LABEL, "parcel data memcpy_s failed, socketId:%{public}d", socketId);
388 return false;
389 }
390 transData->offsets_size = data.GetOffsetsSize() * sizeof(binder_size_t);
391 transData->offsets = transData->buffer_size;
392
393 // remove dbinder PTR data
394 uint32_t cutCount = 0;
395 if (!RemoveDBinderPtrData(transData, cutCount)) {
396 ZLOGE(LOG_LABEL, "RemoveDBinderPtrData fail");
397 return false;
398 }
399 if (cutCount > 0) {
400 OverrideMessageParcelData(transData, data);
401 }
402
403 if (!CheckTransactionData(transData.get())) {
404 ZLOGE(LOG_LABEL, "check trans data fail, socketId:%{public}d", socketId);
405 return false;
406 }
407 if (!IRemoteObjectTranslateWhenSend(transData, socketId, sessionObject)) {
408 ZLOGE(LOG_LABEL, "translate object failed, socketId:%{public}d", socketId);
409 return false;
410 }
411 } else {
412 transData->flags |= TF_STATUS_CODE;
413 transData->buffer_size = sizeof(binder_size_t);
414 transData->offsets_size = static_cast<binder_size_t>(status);
415 transData->offsets = transData->buffer_size;
416 }
417 return true;
418 }
419 } // namespace OHOS
420 #endif // OHOS_IPC_DBINDER_BASE_INVOKER_PROCESS_H