• 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         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