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