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