1 /*
2 * Copyright (C) 2021 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 #include "daemon_usb.h"
16 #include <cerrno>
17 #include <cstddef>
18 #include "arpa/inet.h"
19 #include "asm-generic/int-ll64.h"
20 #include "fcntl.h"
21 #include "linux/usb/functionfs.h"
22 #include "new"
23 #include "sched.h"
24 #include "system_depend.h"
25 #include "unistd.h"
26 #include "uv/unix.h"
27 #include "daemon.h"
28 #include "usb_ffs.h"
29
30 namespace Hdc {
31 static constexpr int CONFIG_COUNT2 = 2;
32 static constexpr int CONFIG_COUNT3 = 3;
33 static constexpr int CONFIG_COUNT5 = 5;
34
35 struct UvData {
36 HdcDaemonUSB *daemonUsb;
37 const uint8_t *buf;
38 };
39
HdcDaemonUSB(const bool serverOrDaemonIn, void *ptrMainBase)40 HdcDaemonUSB::HdcDaemonUSB(const bool serverOrDaemonIn, void *ptrMainBase)
41 : HdcUSBBase(serverOrDaemonIn, ptrMainBase)
42 {
43 }
44
~HdcDaemonUSB()45 HdcDaemonUSB::~HdcDaemonUSB()
46 {
47 // Closed in the IO loop, no longer closing CLOSE ENDPOINT
48 Base::CloseFd(controlEp);
49 if (ctxRecv.buf) {
50 delete[] ctxRecv.buf;
51 }
52 uv_fs_req_cleanup(&ctxRecv.req);
53 }
54
Stop()55 void HdcDaemonUSB::Stop()
56 {
57 WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop");
58 // Here only clean up the IO-related resources, session related resources clear reason to clean up the session
59 // module
60 modRunning = false;
61 WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session");
62 Base::TryCloseHandle((uv_handle_t *)&checkEP);
63 CloseEndpoint(&usbHandle);
64 WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB Stop free main session finish");
65 }
66
GetDevPath(const std::string &path)67 string HdcDaemonUSB::GetDevPath(const std::string &path)
68 {
69 DIR *dir = ::opendir(path.c_str());
70 if (dir == nullptr) {
71 WRITE_LOG(LOG_WARN, "%s: cannot open devpath: errno: %d", path.c_str(), errno);
72 return "";
73 }
74
75 string res = USB_FFS_BASE;
76 string node;
77 int count = 0;
78 struct dirent *entry = nullptr;
79 while ((entry = ::readdir(dir))) {
80 if (*entry->d_name == '.') {
81 continue;
82 }
83 node = entry->d_name;
84 ++count;
85 }
86 if (count > 1) {
87 res += "hdc";
88 } else {
89 res += node;
90 }
91 ::closedir(dir);
92 return res;
93 }
94
GetMaxPacketSize(int fdFfs)95 int HdcDaemonUSB::GetMaxPacketSize(int fdFfs)
96 {
97 // no ioctl support, todo dynamic get
98 return MAX_PACKET_SIZE_HISPEED;
99 }
100
Initial()101 int HdcDaemonUSB::Initial()
102 {
103 // after Linux-3.8,kernel switch to the USB Function FS
104 // Implement USB hdc function in user space
105 WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB init");
106 basePath = GetDevPath(USB_FFS_BASE);
107 if (access((basePath + "/ep0").c_str(), F_OK) != 0) {
108 WRITE_LOG(LOG_DEBUG,"Only support usb-ffs, make sure kernel3.8+ and usb-ffs enabled, "
109 "usbmode disabled: errno: %d, basePath: %s ", errno, basePath.c_str());
110 return ERR_API_FAIL;
111 }
112 ctxRecv.thisClass = this;
113 ctxRecv.bufSizeMax = Base::GetUsbffsBulkSize();
114 ctxRecv.buf = new uint8_t[ctxRecv.bufSizeMax]();
115 if (!ctxRecv.buf) {
116 WRITE_LOG(LOG_FATAL, "Init alloc memory failed");
117 return ERR_BUF_ALLOC;
118 }
119
120 HdcDaemon *daemon = (HdcDaemon *)clsMainBase;
121 WRITE_LOG(LOG_DEBUG, "HdcDaemonUSB::Initiall");
122 uv_timer_init(&daemon->loopMain, &checkEP);
123 checkEP.data = this;
124 uv_timer_start(&checkEP, WatchEPTimer, 0, TIME_BASE);
125 return 0;
126 }
127
128 // make gnuc++ happy. Clang support direct assignment value to structure, buf g++ weakness
FillUsbV2Head(UsbFunctionfsDescV2 &descUsbFfs)129 void HdcDaemonUSB::FillUsbV2Head(UsbFunctionfsDescV2 &descUsbFfs)
130 {
131 descUsbFfs.head.magic = LONG_LE(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
132 descUsbFfs.head.length = LONG_LE(sizeof(descUsbFfs));
133 descUsbFfs.head.flags
134 = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
135 descUsbFfs.config1Count = CONFIG_COUNT3;
136 descUsbFfs.config2Count = CONFIG_COUNT3;
137 descUsbFfs.config3Count = CONFIG_COUNT5;
138 descUsbFfs.configWosCount = CONFIG_COUNT2;
139 descUsbFfs.config1Desc = config1;
140 descUsbFfs.config2Desc = config2;
141 descUsbFfs.config3Desc = config3;
142 descUsbFfs.wosHead = g_wosHead;
143 descUsbFfs.wosDesc = g_wosDesc;
144 descUsbFfs.osPropHead = g_osPropHead;
145 descUsbFfs.osPropValues = g_osPropValues;
146 }
147
148 // DAEMON end USB module USB-FFS EP port connection
ConnectEPPoint(HUSB hUSB)149 int HdcDaemonUSB::ConnectEPPoint(HUSB hUSB)
150 {
151 int ret = ERR_GENERIC;
152 struct UsbFunctionfsDescV2 descUsbFfs = {};
153 FillUsbV2Head(descUsbFfs);
154 while (true) {
155 if (controlEp <= 0) {
156 // After the control port sends the instruction, the device is initialized by the device to the HOST host,
157 // which can be found for USB devices. Do not send initialization to the EP0 control port, the USB
158 // device will not be initialized by Host
159 WRITE_LOG(LOG_DEBUG, "Begin send to control(EP0) for usb descriptor init");
160 string ep0Path = basePath + "/ep0";
161 if ((controlEp = open(ep0Path.c_str(), O_RDWR)) < 0) {
162 WRITE_LOG(LOG_WARN, "%s: cannot open control endpoint: errno=%d", ep0Path.c_str(), errno);
163 break;
164 }
165 if (write(controlEp, &descUsbFfs, sizeof(descUsbFfs)) < 0) {
166 WRITE_LOG(LOG_WARN, "%s: write ffs configs failed: errno=%d", ep0Path.c_str(), errno);
167 break;
168 }
169 if (write(controlEp, &USB_FFS_VALUE, sizeof(USB_FFS_VALUE)) < 0) {
170 WRITE_LOG(LOG_WARN, "%s: write USB_FFS_VALUE failed: errno=%d", ep0Path.c_str(), errno);
171 break;
172 }
173 // active usbrc,Send USB initialization signal
174 SystemDepend::SetDevItem("sys.usb.ffs.ready.hdc", "0");
175 SystemDepend::SetDevItem("sys.usb.ffs.ready", "1");
176 SystemDepend::SetDevItem("sys.usb.ffs.ready.hdc", "1");
177 WRITE_LOG(LOG_DEBUG, "ConnectEPPoint ctrl init finish, set usb-ffs ready");
178 }
179 string outPath = basePath + "/ep1";
180 if ((hUSB->bulkOut = open(outPath.c_str(), O_RDWR)) < 0) {
181 WRITE_LOG(LOG_WARN, "%s: cannot open bulk-out ep: errno=%d", outPath.c_str(), errno);
182 break;
183 }
184 string inPath = basePath + "/ep2";
185 if ((hUSB->bulkIn = open(inPath.c_str(), O_RDWR)) < 0) {
186 WRITE_LOG(LOG_WARN, "%s: cannot open bulk-in ep: errno=%d", inPath.c_str(), errno);
187 break;
188 }
189 // cannot open with O_CLOEXEC, must fcntl
190 fcntl(controlEp, F_SETFD, FD_CLOEXEC);
191 fcntl(hUSB->bulkOut, F_SETFD, FD_CLOEXEC);
192 fcntl(hUSB->bulkIn, F_SETFD, FD_CLOEXEC);
193 hUSB->wMaxPacketSizeSend = GetMaxPacketSize(hUSB->bulkIn);
194
195 WRITE_LOG(LOG_DEBUG, "New bulk in\\out open bulkout:%d bulkin:%d", hUSB->bulkOut, hUSB->bulkIn);
196 ret = RET_SUCCESS;
197 break;
198 }
199 if (ret != RET_SUCCESS) {
200 CloseEndpoint(hUSB, true);
201 }
202 return ret;
203 }
204
CloseEndpoint(HUSB hUSB, bool closeCtrlEp)205 void HdcDaemonUSB::CloseEndpoint(HUSB hUSB, bool closeCtrlEp)
206 {
207 Base::CloseFd(hUSB->bulkIn);
208 Base::CloseFd(hUSB->bulkOut);
209 if (controlEp > 0 && closeCtrlEp) {
210 Base::CloseFd(controlEp);
211 controlEp = 0;
212 }
213 isAlive = false;
214 WRITE_LOG(LOG_FATAL, "DaemonUSB close endpoint");
215 }
216
ResetOldSession(uint32_t sessionId, bool isSoftReset)217 void HdcDaemonUSB::ResetOldSession(uint32_t sessionId, bool isSoftReset)
218 {
219 HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
220 if (sessionId == 0) {
221 sessionId = currentSessionId;
222 }
223 HSession hSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
224 if (hSession == nullptr) {
225 WRITE_LOG(LOG_FATAL, "ResetOldSession hSession nullptr sessionId:%u", sessionId);
226 return;
227 }
228 // The Host side is restarted, but the USB cable is still connected
229 hSession->isSoftReset = isSoftReset;
230 WRITE_LOG(LOG_WARN, "Hostside softreset to restart daemon, old sessionId:%u isSoftReset:%d",
231 sessionId, isSoftReset);
232 daemon->FreeSession(sessionId);
233 }
234
235 // Prevent other USB data misfortunes to send the program crash
AvailablePacket(uint8_t *ioBuf, int ioBytes, uint32_t *sessionId)236 int HdcDaemonUSB::AvailablePacket(uint8_t *ioBuf, int ioBytes, uint32_t *sessionId)
237 {
238 int ret = RET_SUCCESS;
239 while (true) {
240 if (!IsUsbPacketHeader(ioBuf, ioBytes)) {
241 break;
242 }
243 // usb header
244 USBHead *usbPayloadHeader = reinterpret_cast<struct USBHead *>(ioBuf);
245 uint32_t inSessionId = ntohl(usbPayloadHeader->sessionId);
246 if ((usbPayloadHeader->option & USB_OPTION_RESET)) {
247 WRITE_LOG(LOG_INFO, "USB_OPTION_RESET inSessionId:%u, currentSessionId:%u",
248 inSessionId, currentSessionId);
249 ResetOldSession(inSessionId, true);
250 ret = ERR_IO_SOFT_RESET;
251 break;
252 }
253 *sessionId = inSessionId;
254 break;
255 }
256 return ret;
257 }
258
259 // Work in subcrete,Work thread is ready
ReadyForWorkThread(HSession hSession)260 bool HdcDaemonUSB::ReadyForWorkThread(HSession hSession)
261 {
262 HdcUSBBase::ReadyForWorkThread(hSession);
263 return true;
264 };
265
CloseBulkEp(bool bulkInOut, int bulkFd, uv_loop_t *loop)266 int HdcDaemonUSB::CloseBulkEp(bool bulkInOut, int bulkFd, uv_loop_t *loop)
267 {
268 struct CtxCloseBulkEp {
269 uv_fs_t req;
270 HdcDaemonUSB *thisClass;
271 bool bulkInOut;
272 };
273 CtxCloseBulkEp *ctx = new(std::nothrow) CtxCloseBulkEp();
274 if (ctx == nullptr) {
275 WRITE_LOG(LOG_FATAL, "CloseBulkEp new ctx failed");
276 return -1;
277 }
278 uv_fs_t *req = &ctx->req;
279 req->data = ctx;
280 ctx->bulkInOut = bulkInOut;
281 ctx->thisClass = this;
282 isAlive = false;
283 WRITE_LOG(LOG_DEBUG, "CloseBulkEp bulkFd:%d", bulkFd);
284 uv_fs_close(loop, req, bulkFd, [](uv_fs_t *req) {
285 auto ctx = (CtxCloseBulkEp *)req->data;
286 WRITE_LOG(LOG_DEBUG, "Try to abort blukin write callback %s", ctx->bulkInOut ? "bulkin" : "bulkout");
287 if (ctx->bulkInOut) {
288 ctx->thisClass->usbHandle.bulkIn = 0;
289 } else {
290 ctx->thisClass->usbHandle.bulkOut = 0;
291 }
292 uv_fs_req_cleanup(req);
293 delete ctx;
294 });
295 return 0;
296 }
297
SendUSBIOSync(HSession hSession, HUSB hMainUSB, const uint8_t *data, const int length)298 int HdcDaemonUSB::SendUSBIOSync(HSession hSession, HUSB hMainUSB, const uint8_t *data, const int length)
299 {
300 int bulkIn = hMainUSB->bulkIn;
301 int childRet = 0;
302 int ret = ERR_IO_FAIL;
303 int offset = 0;
304 StartTraceScope("HdcDaemonUSB::SendUSBIOSync");
305 while (modRunning && isAlive && !hSession->isDead) {
306 childRet = write(bulkIn, const_cast<uint8_t *>(data) + offset, length - offset);
307 if (childRet <= 0) {
308 int err = errno;
309 if (err == EINTR) {
310 WRITE_LOG(LOG_WARN, "BulkinWrite write EINTR, try again, offset:%u bulkIn:%d bulkOut:%d",
311 offset, bulkIn, hMainUSB->bulkOut);
312 continue;
313 } else {
314 WRITE_LOG(LOG_FATAL, "BulkinWrite write fatal errno %d", err);
315 isAlive = false;
316 }
317 break;
318 }
319 offset += childRet;
320 if (offset >= length) {
321 break;
322 }
323 }
324 if (offset == length) {
325 ret = length;
326 } else {
327 WRITE_LOG(LOG_FATAL, "BulkinWrite write failed, nsize:%d really:%d modRunning:%d isAlive:%d SessionDead:%d",
328 length, offset, modRunning, isAlive, hSession->isDead);
329 }
330 return ret;
331 }
332
SendUSBRaw(HSession hSession, uint8_t *data, const int length)333 int HdcDaemonUSB::SendUSBRaw(HSession hSession, uint8_t *data, const int length)
334 {
335 StartTraceScope("HdcDaemonUSB::SendUSBRaw");
336 HdcDaemon *daemon = (HdcDaemon *)hSession->classInstance;
337 uint32_t sessionId = hSession->sessionId;
338 std::unique_lock<std::mutex> lock(mutexUsbFfs);
339 if (Base::IsSessionDeleted(sessionId)) {
340 WRITE_LOG(LOG_DEBUG, "SendUSBRaw session %u is deleted", sessionId);
341 return ERR_SESSION_DEAD;
342 }
343 ++hSession->ref;
344 int ret = SendUSBIOSync(hSession, &usbHandle, data, length);
345 --hSession->ref;
346 if (ret < 0) {
347 daemon->FreeSession(hSession->sessionId);
348 WRITE_LOG(LOG_DEBUG, "SendUSBRaw try to freesession");
349 }
350 return ret;
351 }
352
353 // cross thread call
OnNewHandshakeOK(const uint32_t sessionId)354 void HdcDaemonUSB::OnNewHandshakeOK(const uint32_t sessionId)
355 {
356 currentSessionId = sessionId; // sync with server, and set server's real Id
357 }
358
359 // MainThreadCall, when seession was freed
OnSessionFreeFinally(const HSession hSession)360 void HdcDaemonUSB::OnSessionFreeFinally(const HSession hSession)
361 {
362 WRITE_LOG(LOG_DEBUG, "OnSessionFreeFinally sid:%u currentsid:%u", hSession->sessionId, currentSessionId);
363 if (hSession->isSoftReset) {
364 WRITE_LOG(LOG_INFO, "OnSessionFreeFinally sid:%u softreset", hSession->sessionId);
365 return;
366 }
367 if (currentSessionId == hSession->sessionId) {
368 WRITE_LOG(LOG_DEBUG, "OnSessionFreeFinally set isAlive false");
369 isAlive = false;
370 // uv_cancel ctxRecv.req == UV_EBUSY, not effect immediately. It must be close by logic
371 }
372 }
373
PrepareNewSession(uint32_t sessionId, uint8_t *pRecvBuf, int recvBytesIO)374 HSession HdcDaemonUSB::PrepareNewSession(uint32_t sessionId, uint8_t *pRecvBuf, int recvBytesIO)
375 {
376 HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
377 StartTraceScope("HdcDaemonUSB::PrepareNewSession");
378 HSession hChildSession = daemon->MallocSession(false, CONN_USB, this, sessionId);
379 if (!hChildSession) {
380 WRITE_LOG(LOG_FATAL, "malloc session failed sessionId:%u", sessionId);
381 return nullptr;
382 }
383 currentSessionId = sessionId;
384 Base::StartWorkThread(&daemon->loopMain, daemon->SessionWorkThread, Base::FinishWorkThread, hChildSession);
385
386 HSessionInfo hSessionInfo = new(std::nothrow) HdcSessionInfo();
387 if (hSessionInfo == nullptr) {
388 WRITE_LOG(LOG_FATAL, "PrepareNewSession new hSessionInfo failed");
389 return nullptr;
390 }
391 hSessionInfo->sessionId = hChildSession->sessionId;
392 hSessionInfo->classInstance = hChildSession->classInstance;
393 hSessionInfo->classModule = hChildSession->classModule;
394 hSessionInfo->hSession = hChildSession;
395 auto funcNewSessionUp = [](uv_timer_t *handle) -> void {
396 HSessionInfo hSessionInfo = reinterpret_cast<HSessionInfo>(handle->data);
397 if (hSessionInfo == nullptr) {
398 Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
399 WRITE_LOG(LOG_FATAL, "hSessionInfo is null");
400 return;
401 }
402 HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(hSessionInfo->classInstance);
403 if (Base::IsSessionDeleted(hSessionInfo->sessionId)) {
404 WRITE_LOG(LOG_INFO, "funcNewSessionUp session is deleted");
405 delete hSessionInfo;
406 handle->data = nullptr;
407 Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
408 return;
409 }
410 HSession hChildSession = hSessionInfo->hSession;
411 if (hChildSession->childLoop.active_handles == 0) {
412 return;
413 }
414 if (!hChildSession->isDead) {
415 auto ctrl = daemon->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0);
416 Base::SendToPollFd(hChildSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
417 WRITE_LOG(LOG_DEBUG, "Main thread usbio migrate finish");
418 }
419 delete hSessionInfo;
420 handle->data = nullptr;
421 Base::TryCloseHandle(reinterpret_cast<uv_handle_t *>(handle), Base::CloseTimerCallback);
422 };
423 Base::TimerUvTask(&daemon->loopMain, hSessionInfo, funcNewSessionUp);
424 return hChildSession;
425 }
426
UvWriteCallback(uv_write_t *req, int status)427 void HdcDaemonUSB::UvWriteCallback(uv_write_t *req, int status)
428 {
429 StartTraceScope("HdcDaemonUSB::UvWriteCallback");
430 if (status < 0) {
431 constexpr int bufSize = 1024;
432 char buf[bufSize] = { 0 };
433 uv_strerror_r(status, buf, bufSize);
434 WRITE_LOG(LOG_WARN, "SendCallback failed,status:%d %s", status, buf);
435 }
436 UvData *uvData = reinterpret_cast<UvData *>(req->data);
437 if (uvData) {
438 #ifndef CONFIG_USE_JEMALLOC_DFX_INIF
439 uvData->daemonUsb->cirbuf.Free(uvData->buf);
440 #else
441 delete[] uvData->buf;
442 #endif
443 delete uvData;
444 }
445 delete req;
446 }
447
UsbToStream(uv_stream_t *stream, const uint8_t *buf, const int size)448 int HdcDaemonUSB::UsbToStream(uv_stream_t *stream, const uint8_t *buf, const int size)
449 {
450 StartTraceScope("HdcDaemonUSB::UsbToStream");
451 int ret = ERR_GENERIC;
452 uv_write_t *reqWrite = new uv_write_t();
453 if (!reqWrite) {
454 WRITE_LOG(LOG_WARN, "UsbToStream new write_t failed size:%d", size);
455 #ifndef CONFIG_USE_JEMALLOC_DFX_INIF
456 cirbuf.Free(buf);
457 #else
458 delete[] buf;
459 #endif
460 return ERR_BUF_ALLOC;
461 }
462 uv_buf_t bfr;
463 while (true) {
464 UvData *uvData = new(std::nothrow) UvData();
465 if (uvData == nullptr) {
466 WRITE_LOG(LOG_FATAL, "UsbToStream new uvData failed size:%d", size);
467 #ifndef CONFIG_USE_JEMALLOC_DFX_INIF
468 cirbuf.Free(buf);
469 #else
470 delete[] buf;
471 #endif
472 delete reqWrite;
473 return ERR_BUF_ALLOC;
474 }
475 uvData->daemonUsb = this;
476 uvData->buf = buf;
477 reqWrite->data = reinterpret_cast<void *>(uvData);
478 bfr.base = (char *)buf;
479 bfr.len = size;
480 if (!uv_is_writable(stream)) {
481 WRITE_LOG(LOG_WARN, "UsbToStream uv_is_writable false size:%d", size);
482 delete reqWrite;
483 #ifndef CONFIG_USE_JEMALLOC_DFX_INIF
484 cirbuf.Free(buf);
485 #else
486 delete[] buf;
487 #endif
488 delete uvData;
489 break;
490 }
491 ret = uv_write(reqWrite, stream, &bfr, 1, UvWriteCallback);
492 if (ret < 0) {
493 WRITE_LOG(LOG_WARN, "UsbToStream uv_write false ret:%d", ret);
494 delete reqWrite;
495 #ifndef CONFIG_USE_JEMALLOC_DFX_INIF
496 cirbuf.Free(buf);
497 #else
498 delete[] buf;
499 #endif
500 delete uvData;
501 ret = ERR_IO_FAIL;
502 break;
503 }
504 ret = size;
505 break;
506 }
507 return ret;
508 }
509
UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)510 int HdcDaemonUSB::UsbToHdcProtocol(uv_stream_t *stream, uint8_t *appendData, int dataSize)
511 {
512 StartTraceScope("HdcDaemonUSB::UsbToHdcProtocol");
513 #ifndef CONFIG_USE_JEMALLOC_DFX_INIF
514 uint8_t *data = cirbuf.Malloc();
515 #else
516 uint8_t *data = new uint8_t[dataSize];
517 #endif
518 if (data == nullptr) {
519 WRITE_LOG(LOG_WARN, "UsbToHdcProtocol data nullptr");
520 return -1;
521 }
522 if (memcpy_s(data, dataSize, appendData, dataSize)) {
523 WRITE_LOG(LOG_WARN, "UsbToHdcProtocol memory copy failed dataSize:%d", dataSize);
524 #ifndef CONFIG_USE_JEMALLOC_DFX_INIF
525 cirbuf.Free(data);
526 #else
527 delete[] data;
528 #endif
529 return ERR_BUF_COPY;
530 }
531 return UsbToStream(stream, data, dataSize);
532 }
533
DispatchToWorkThread(uint32_t sessionId, uint8_t *readBuf, int readBytes)534 int HdcDaemonUSB::DispatchToWorkThread(uint32_t sessionId, uint8_t *readBuf, int readBytes)
535 {
536 HSession hChildSession = nullptr;
537 HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
538 int childRet = RET_SUCCESS;
539 StartTraceScope("HdcDaemonUSB::DispatchToWorkThread");
540 if (sessionId == 0) {
541 // hdc packet data
542 sessionId = currentSessionId;
543 }
544 if (currentSessionId != 0 && sessionId != currentSessionId) {
545 WRITE_LOG(LOG_WARN, "New session coming, restart old sessionId:%u", currentSessionId);
546 ResetOldSession(currentSessionId);
547 currentSessionId = 0;
548 }
549 hChildSession = daemon->AdminSession(OP_QUERY, sessionId, nullptr);
550 if (!hChildSession) {
551 hChildSession = PrepareNewSession(sessionId, readBuf, readBytes);
552 if (!hChildSession) {
553 WRITE_LOG(LOG_WARN, "prep new session err for sessionId:%u", sessionId);
554 return ERR_SESSION_NOFOUND;
555 }
556 }
557
558 if (hChildSession->childCleared || hChildSession->isDead) {
559 WRITE_LOG(LOG_WARN, "session dead clr:%d - %d", hChildSession->childCleared, hChildSession->isDead);
560 return ERR_SESSION_DEAD;
561 }
562 uv_stream_t *stream = reinterpret_cast<uv_stream_t *>(&hChildSession->dataPipe[STREAM_MAIN]);
563 if ((childRet = SendToHdcStream(hChildSession, stream, readBuf, readBytes)) < 0) {
564 WRITE_LOG(LOG_WARN, "DispatchToWorkThread SendToHdcStream err ret:%d", childRet);
565 return ERR_IO_FAIL;
566 }
567 return childRet;
568 }
569
JumpAntiquePacket(const uint8_t &buf, ssize_t bytes) const570 bool HdcDaemonUSB::JumpAntiquePacket(const uint8_t &buf, ssize_t bytes) const
571 {
572 constexpr size_t antiqueFlagSize = 4;
573 constexpr size_t antiqueFullSize = 24;
574 // anti CNXN 0x4e584e43
575 uint8_t flag[] = { 0x43, 0x4e, 0x58, 0x4e };
576 if (bytes == antiqueFullSize && !memcmp(&buf, flag, antiqueFlagSize)) {
577 return true;
578 }
579 return false;
580 }
581
582 // Only physically swap EP ports will be reset
OnUSBRead(uv_fs_t *req)583 void HdcDaemonUSB::OnUSBRead(uv_fs_t *req)
584 { // Only read at the main thread
585 StartTraceScope("HdcDaemonUSB::OnUSBRead");
586 auto ctxIo = reinterpret_cast<CtxUvFileCommonIo *>(req->data);
587 auto hUSB = reinterpret_cast<HUSB>(ctxIo->data);
588 auto thisClass = reinterpret_cast<HdcDaemonUSB *>(ctxIo->thisClass);
589 uint8_t *bufPtr = ctxIo->buf;
590 ssize_t bytesIOBytes = req->result;
591 uint32_t sessionId = 0;
592 bool ret = false;
593 int childRet = 0;
594 if (bytesIOBytes > hUSB->wMaxPacketSizeSend && bytesIOBytes != thisClass->saveNextReadSize) {
595 WRITE_LOG(LOG_WARN, "Not full packet, wanted:%d really:%d", thisClass->saveNextReadSize, bytesIOBytes);
596 }
597 while (thisClass->isAlive) {
598 // Don't care is module running, first deal with this
599 if (bytesIOBytes < 0) {
600 // logic alive and EINTER is gdb attach
601 //
602 // [about gdb attach known issue]
603 // When GDB debugging is loaded, the number of USB read interrupts of libuv will increase. Multiple
604 // interrupts will increase the correctness of USB data reading. Setting GDB to asynchronous mode or using
605 // log debugging can avoid this problem
606 if (bytesIOBytes != -EINTR) { // Epoll will be broken when gdb attach
607 constexpr int bufSize = 1024;
608 char buf[bufSize] = { 0 };
609 uv_strerror_r(bytesIOBytes, buf, bufSize);
610 WRITE_LOG(LOG_WARN, "USBIO ret:%d failed:%s", bytesIOBytes, buf);
611 ret = false;
612 break;
613 } else {
614 WRITE_LOG(LOG_ALL, "OnUSBRead signal EINTR");
615 }
616 } else if (bytesIOBytes == 0) { // zero packet
617 WRITE_LOG(LOG_ALL, "Zero packet received");
618 } else {
619 if (thisClass->JumpAntiquePacket(*bufPtr, bytesIOBytes)) {
620 WRITE_LOG(LOG_DEBUG, "JumpAntiquePacket auto jump");
621 ret = true;
622 break;
623 }
624 // guess is head of packet
625 if ((childRet = thisClass->AvailablePacket((uint8_t *)bufPtr, bytesIOBytes, &sessionId)) != RET_SUCCESS) {
626 if (childRet != ERR_IO_SOFT_RESET) {
627 WRITE_LOG(LOG_WARN, "AvailablePacket check failed, ret:%d buf:%-50s", bytesIOBytes, bufPtr);
628 break;
629 }
630 // reset packet
631 childRet = 0; // need max size
632 } else {
633 // AvailablePacket case
634 if ((childRet = thisClass->DispatchToWorkThread(sessionId, bufPtr, bytesIOBytes)) < 0) {
635 WRITE_LOG(LOG_FATAL, "DispatchToWorkThread failed");
636 break;
637 }
638 }
639 }
640 int nextReadSize = childRet == 0 ? hUSB->wMaxPacketSizeSend : std::min(childRet, Base::GetUsbffsBulkSize());
641 thisClass->saveNextReadSize = nextReadSize;
642 if (thisClass->LoopUSBRead(hUSB, nextReadSize) < 0) {
643 WRITE_LOG(LOG_FATAL, "LoopUSBRead failed");
644 break;
645 }
646 ret = true;
647 break;
648 }
649 if (!ret) {
650 WRITE_LOG(LOG_INFO, "OnUSBRead ret false, set isAlive = false");
651 thisClass->isAlive = false;
652 thisClass->ctxRecv.atPollQueue = false;
653 }
654 }
655
LoopUSBRead(HUSB hUSB, int readMaxWanted)656 int HdcDaemonUSB::LoopUSBRead(HUSB hUSB, int readMaxWanted)
657 {
658 StartTraceScope("HdcDaemonUSB::LoopUSBRead");
659 int ret = ERR_GENERIC;
660 HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(clsMainBase);
661 if (daemon == nullptr) {
662 WRITE_LOG(LOG_FATAL, "daemon is nullptr in LoopUSBRead");
663 return ret;
664 }
665 uv_buf_t iov;
666 ctxRecv.data = hUSB;
667 ctxRecv.bufSize = readMaxWanted;
668 ctxRecv.req = {};
669 uv_fs_t *req = &ctxRecv.req;
670 req->data = &ctxRecv;
671 iov = uv_buf_init(reinterpret_cast<char *>(ctxRecv.buf), ctxRecv.bufSize);
672 ret = uv_fs_read(&daemon->loopMain, req, hUSB->bulkOut, &iov, 1, -1, OnUSBRead);
673 if (ret < 0) {
674 WRITE_LOG(LOG_FATAL, "uv_fs_read ret:%d < 0", ret);
675 return ERR_API_FAIL;
676 }
677 ctxRecv.atPollQueue = true;
678 return RET_SUCCESS;
679 }
680
681 // Because USB can connect to only one host,daemonUSB is only one Session by default
WatchEPTimer(uv_timer_t *handle)682 void HdcDaemonUSB::WatchEPTimer(uv_timer_t *handle)
683 {
684 HdcDaemonUSB *thisClass = (HdcDaemonUSB *)handle->data;
685 HUSB hUSB = &thisClass->usbHandle;
686 HdcDaemon *daemon = reinterpret_cast<HdcDaemon *>(thisClass->clsMainBase);
687 if (thisClass->isAlive || thisClass->ctxRecv.atPollQueue) {
688 return;
689 }
690 bool resetEp = false;
691 do {
692 if (hUSB->bulkIn > 0) {
693 WRITE_LOG(LOG_DEBUG, "Watchdog close bulkin");
694 thisClass->CloseBulkEp(true, thisClass->usbHandle.bulkIn, &daemon->loopMain);
695 resetEp = true;
696 }
697 if (hUSB->bulkOut > 0) {
698 WRITE_LOG(LOG_DEBUG, "Watchdog close bulkout");
699 thisClass->CloseBulkEp(false, thisClass->usbHandle.bulkOut, &daemon->loopMain);
700 resetEp = true;
701 }
702 if (thisClass->controlEp > 0) {
703 Base::CloseFd(thisClass->controlEp);
704 resetEp = true;
705 }
706 } while (false);
707 if (resetEp || thisClass->usbHandle.bulkIn != 0 || thisClass->usbHandle.bulkOut != 0) {
708 return;
709 }
710 // until all bulkport reset
711 if (thisClass->ConnectEPPoint(hUSB) != RET_SUCCESS) {
712 WRITE_LOG(LOG_DEBUG, "WatchEPTimer ConnectEPPoint failed");
713 return;
714 }
715 // connect OK
716 thisClass->isAlive = true;
717 thisClass->LoopUSBRead(hUSB, hUSB->wMaxPacketSizeSend);
718 }
719 } // namespace Hdc
720