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