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