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