• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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