xref: /developtools/hdc/src/common/session.cpp (revision cc290419)
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 "session.h"
16#ifndef TEST_HASH
17#include "hdc_hash_gen.h"
18#endif
19#include "serial_struct.h"
20
21namespace Hdc {
22HdcSessionBase::HdcSessionBase(bool serverOrDaemonIn, size_t uvThreadSize)
23{
24    // print version pid
25    WRITE_LOG(LOG_INFO, "Program running. %s Pid:%u", Base::GetVersion().c_str(), getpid());
26    // server/daemon common initialization code
27    if (uvThreadSize < SIZE_THREAD_POOL_MIN) {
28        uvThreadSize = SIZE_THREAD_POOL_MIN;
29    } else if (uvThreadSize > SIZE_THREAD_POOL_MAX) {
30        uvThreadSize = SIZE_THREAD_POOL_MAX;
31    }
32    threadPoolCount = uvThreadSize;
33    WRITE_LOG(LOG_INFO, "set UV_THREADPOOL_SIZE:%zu", threadPoolCount);
34    string uvThreadEnv("UV_THREADPOOL_SIZE");
35    string uvThreadVal = std::to_string(threadPoolCount);
36#ifdef _WIN32
37    uvThreadEnv += "=";
38    uvThreadEnv += uvThreadVal;
39    _putenv(uvThreadEnv.c_str());
40#else
41    setenv(uvThreadEnv.c_str(), uvThreadVal.c_str(), 1);
42#endif
43    uv_loop_init(&loopMain);
44    WRITE_LOG(LOG_DEBUG, "loopMain init");
45    uv_rwlock_init(&mainAsync);
46#ifndef FUZZ_TEST
47    uv_async_init(&loopMain, &asyncMainLoop, MainAsyncCallback);
48#endif
49    uv_rwlock_init(&lockMapSession);
50    serverOrDaemon = serverOrDaemonIn;
51    ctxUSB = nullptr;
52    wantRestart = false;
53    threadSessionMain = uv_thread_self();
54
55#ifdef HDC_HOST
56    if (serverOrDaemon) {
57        if (libusb_init((libusb_context **)&ctxUSB) != 0) {
58            ctxUSB = nullptr;
59            WRITE_LOG(LOG_FATAL, "libusb_init failed ctxUSB is nullptr");
60        }
61    }
62#endif
63}
64
65HdcSessionBase::~HdcSessionBase()
66{
67#ifndef FUZZ_TEST
68    Base::TryCloseHandle((uv_handle_t *)&asyncMainLoop);
69#endif
70    uv_loop_close(&loopMain);
71    // clear base
72    uv_rwlock_destroy(&mainAsync);
73    uv_rwlock_destroy(&lockMapSession);
74#ifdef HDC_HOST
75    if (serverOrDaemon and ctxUSB != nullptr) {
76        libusb_exit((libusb_context *)ctxUSB);
77    }
78#endif
79    WRITE_LOG(LOG_WARN, "~HdcSessionBase free sessionRef:%u instance:%s", uint32_t(sessionRef),
80              serverOrDaemon ? "server" : "daemon");
81}
82
83// remove step2
84bool HdcSessionBase::TryRemoveTask(HTaskInfo hTask)
85{
86    if (hTask->taskFree) {
87        WRITE_LOG(LOG_WARN, "TryRemoveTask channelId:%u", hTask->channelId);
88        return true;
89    }
90    bool ret = RemoveInstanceTask(OP_REMOVE, hTask);
91    if (ret) {
92        hTask->taskFree = true;
93    } else {
94        // This is used to check that the memory cannot be cleaned up. If the memory cannot be released, break point
95        // here to see which task has not been released
96        // print task clear
97    }
98    return ret;
99}
100
101// remove step1
102void HdcSessionBase::BeginRemoveTask(HTaskInfo hTask)
103{
104    StartTraceScope("HdcSessionBase::BeginRemoveTask");
105    if (hTask->taskStop || hTask->taskFree) {
106        WRITE_LOG(LOG_WARN, "BeginRemoveTask channelId:%u taskStop:%d taskFree:%d",
107            hTask->channelId, hTask->taskStop, hTask->taskFree);
108        return;
109    }
110
111    WRITE_LOG(LOG_WARN, "BeginRemoveTask taskType:%d channelId:%u", hTask->taskType, hTask->channelId);
112    auto taskClassDeleteRetry = [](uv_timer_t *handle) -> void {
113        StartTraceScope("HdcSessionBase::BeginRemoveTask taskClassDeleteRetry");
114        HTaskInfo hTask = (HTaskInfo)handle->data;
115        HdcSessionBase *thisClass = (HdcSessionBase *)hTask->ownerSessionClass;
116        if (hTask->isCleared == false) {
117            hTask->isCleared = true;
118            WRITE_LOG(LOG_WARN, "taskClassDeleteRetry start clear task, taskType:%d cid:%u sid:%u",
119                hTask->taskType, hTask->channelId, hTask->sessionId);
120            bool ret = thisClass->RemoveInstanceTask(OP_CLEAR, hTask);
121            if (!ret) {
122                WRITE_LOG(LOG_WARN, "taskClassDeleteRetry RemoveInstanceTask return false taskType:%d cid:%u sid:%u",
123                    hTask->taskType, hTask->channelId, hTask->sessionId);
124            }
125        }
126
127        constexpr uint32_t count = 1000;
128        if (hTask->closeRetryCount == 0 || hTask->closeRetryCount > count) {
129            WRITE_LOG(LOG_DEBUG, "TaskDelay task remove retry count %d/%d, taskType:%d channelId:%u, sessionId:%u",
130                hTask->closeRetryCount, GLOBAL_TIMEOUT, hTask->taskType, hTask->channelId, hTask->sessionId);
131            hTask->closeRetryCount = 1;
132        }
133        hTask->closeRetryCount++;
134        if (!thisClass->TryRemoveTask(hTask)) {
135            WRITE_LOG(LOG_WARN, "TaskDelay TryRemoveTask false channelId:%u", hTask->channelId);
136            return;
137        }
138        WRITE_LOG(LOG_WARN, "TaskDelay task remove finish, channelId:%u", hTask->channelId);
139        if (hTask != nullptr) {
140            delete hTask;
141            hTask = nullptr;
142        }
143        Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback);
144    };
145    Base::TimerUvTask(hTask->runLoop, hTask, taskClassDeleteRetry, (GLOBAL_TIMEOUT * TIME_BASE) / UV_DEFAULT_INTERVAL);
146
147    hTask->taskStop = true;
148}
149
150// Clear all Task or a single Task, the regular situation is stopped first, and the specific class memory is cleaned up
151// after the end of the LOOP.
152// When ChannelIdinput == 0, at this time, all of the LOOP ends, all runs in the class end, so directly skip STOP,
153// physical memory deletion class trimming
154void HdcSessionBase::ClearOwnTasks(HSession hSession, const uint32_t channelIDInput)
155{
156    // First case: normal task cleanup process (STOP Remove)
157    // Second: The task is cleaned up, the session ends
158    // Third: The task is cleaned up, and the session is directly over the session.
159    StartTraceScope("HdcSessionBase::ClearOwnTasks");
160    hSession->mapTaskMutex.lock();
161    map<uint32_t, HTaskInfo>::iterator iter;
162    for (iter = hSession->mapTask->begin(); iter != hSession->mapTask->end();) {
163        uint32_t channelId = iter->first;
164        HTaskInfo hTask = iter->second;
165        if (channelIDInput != 0) {  // single
166            if (channelIDInput != channelId) {
167                ++iter;
168                continue;
169            }
170            BeginRemoveTask(hTask);
171            WRITE_LOG(LOG_WARN, "ClearOwnTasks OP_CLEAR finish, sessionId:%u channelIDInput:%u",
172                hSession->sessionId, channelIDInput);
173            iter = hSession->mapTask->erase(iter);
174            break;
175        }
176        // multi
177        BeginRemoveTask(hTask);
178        iter = hSession->mapTask->erase(iter);
179    }
180    hSession->mapTaskMutex.unlock();
181}
182
183void HdcSessionBase::ClearSessions()
184{
185    // no need to lock mapSession
186    // broadcast free signal
187    for (auto v : mapSession) {
188        HSession hSession = (HSession)v.second;
189        if (!hSession->isDead) {
190            FreeSession(hSession->sessionId);
191        }
192    }
193}
194
195void HdcSessionBase::ReMainLoopForInstanceClear()
196{  // reloop
197    StartTraceScope("HdcSessionBase::ReMainLoopForInstanceClear");
198    auto clearSessionsForFinish = [](uv_idle_t *handle) -> void {
199        HdcSessionBase *thisClass = (HdcSessionBase *)handle->data;
200        if (thisClass->sessionRef > 0) {
201            return;
202        }
203        // all task has been free
204        uv_close((uv_handle_t *)handle, Base::CloseIdleCallback);
205        uv_stop(&thisClass->loopMain);
206    };
207    Base::IdleUvTask(&loopMain, this, clearSessionsForFinish);
208    uv_run(&loopMain, UV_RUN_DEFAULT);
209};
210
211#ifdef HDC_SUPPORT_UART
212void HdcSessionBase::EnumUARTDeviceRegister(UartKickoutZombie kickOut)
213{
214    uv_rwlock_rdlock(&lockMapSession);
215    map<uint32_t, HSession>::iterator i;
216    for (i = mapSession.begin(); i != mapSession.end(); ++i) {
217        HSession hs = i->second;
218        if ((hs->connType != CONN_SERIAL) or (hs->hUART == nullptr)) {
219            continue;
220        }
221        kickOut(hs);
222        break;
223    }
224    uv_rwlock_rdunlock(&lockMapSession);
225}
226#endif
227
228void HdcSessionBase::EnumUSBDeviceRegister(void (*pCallBack)(HSession hSession))
229{
230    if (!pCallBack) {
231        return;
232    }
233    uv_rwlock_rdlock(&lockMapSession);
234    map<uint32_t, HSession>::iterator i;
235    for (i = mapSession.begin(); i != mapSession.end(); ++i) {
236        HSession hs = i->second;
237        if (hs->connType != CONN_USB) {
238            continue;
239        }
240        if (hs->hUSB == nullptr) {
241            continue;
242        }
243        if (pCallBack) {
244            pCallBack(hs);
245        }
246        break;
247    }
248    uv_rwlock_rdunlock(&lockMapSession);
249}
250
251// The PC side gives the device information, determines if the USB device is registered
252// PDEV and Busid Devid two choices
253HSession HdcSessionBase::QueryUSBDeviceRegister(void *pDev, uint8_t busIDIn, uint8_t devIDIn)
254{
255#ifdef HDC_HOST
256    libusb_device *dev = (libusb_device *)pDev;
257    HSession hResult = nullptr;
258    if (!mapSession.size()) {
259        return nullptr;
260    }
261    uint8_t busId = 0;
262    uint8_t devId = 0;
263    if (pDev) {
264        busId = libusb_get_bus_number(dev);
265        devId = libusb_get_device_address(dev);
266    } else {
267        busId = busIDIn;
268        devId = devIDIn;
269    }
270    uv_rwlock_rdlock(&lockMapSession);
271    map<uint32_t, HSession>::iterator i;
272    for (i = mapSession.begin(); i != mapSession.end(); ++i) {
273        HSession hs = i->second;
274        if (hs->connType == CONN_USB) {
275            continue;
276        }
277        if (hs->hUSB == nullptr) {
278            continue;
279        }
280        if (hs->hUSB->devId != devId || hs->hUSB->busId != busId) {
281            continue;
282        }
283        hResult = hs;
284        break;
285    }
286    uv_rwlock_rdunlock(&lockMapSession);
287    return hResult;
288#else
289    return nullptr;
290#endif
291}
292
293void HdcSessionBase::AsyncMainLoopTask(uv_idle_t *handle)
294{
295    AsyncParam *param = (AsyncParam *)handle->data;
296    HdcSessionBase *thisClass = (HdcSessionBase *)param->thisClass;
297    switch (param->method) {
298        case ASYNC_FREE_SESSION:
299            // Destruction is unified in the main thread
300            thisClass->FreeSession(param->sid);
301            break;
302        case ASYNC_STOP_MAINLOOP:
303            uv_stop(&thisClass->loopMain);
304            break;
305        default:
306            break;
307    }
308    if (param->data) {
309        delete[]((uint8_t *)param->data);
310    }
311    delete param;
312    param = nullptr;
313    Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseIdleCallback);
314}
315
316void HdcSessionBase::MainAsyncCallback(uv_async_t *handle)
317{
318    HdcSessionBase *thisClass = (HdcSessionBase *)handle->data;
319    list<void *>::iterator i;
320    list<void *> &lst = thisClass->lstMainThreadOP;
321    uv_rwlock_wrlock(&thisClass->mainAsync);
322    for (i = lst.begin(); i != lst.end();) {
323        AsyncParam *param = (AsyncParam *)*i;
324        Base::IdleUvTask(&thisClass->loopMain, param, AsyncMainLoopTask);
325        i = lst.erase(i);
326    }
327    uv_rwlock_wrunlock(&thisClass->mainAsync);
328}
329
330void HdcSessionBase::PushAsyncMessage(const uint32_t sessionId, const uint8_t method, const void *data,
331                                      const int dataSize)
332{
333    AsyncParam *param = new AsyncParam();
334    if (!param) {
335        return;
336    }
337    param->sid = sessionId;
338    param->thisClass = this;
339    param->method = method;
340    if (dataSize > 0) {
341        param->dataSize = dataSize;
342        param->data = new uint8_t[param->dataSize]();
343        if (!param->data) {
344            delete param;
345            return;
346        }
347        if (memcpy_s((uint8_t *)param->data, param->dataSize, data, dataSize)) {
348            delete[]((uint8_t *)param->data);
349            delete param;
350            return;
351        }
352    }
353
354    asyncMainLoop.data = this;
355    uv_rwlock_wrlock(&mainAsync);
356    lstMainThreadOP.push_back(param);
357    uv_rwlock_wrunlock(&mainAsync);
358    uv_async_send(&asyncMainLoop);
359}
360
361void HdcSessionBase::WorkerPendding()
362{
363    uv_run(&loopMain, UV_RUN_DEFAULT);
364    ClearInstanceResource();
365}
366
367int HdcSessionBase::MallocSessionByConnectType(HSession hSession)
368{
369    int ret = 0;
370    switch (hSession->connType) {
371        case CONN_TCP: {
372            uv_tcp_init(&loopMain, &hSession->hWorkTCP);
373            ++hSession->uvHandleRef;
374            hSession->hWorkTCP.data = hSession;
375            break;
376        }
377        case CONN_USB: {
378            // Some members need to be placed at the primary thread
379            HUSB hUSB = new HdcUSB();
380            if (!hUSB) {
381                ret = -1;
382                break;
383            }
384            hSession->hUSB = hUSB;
385            hSession->hUSB->wMaxPacketSizeSend = MAX_PACKET_SIZE_HISPEED;
386            break;
387        }
388#ifdef HDC_SUPPORT_UART
389        case CONN_SERIAL: {
390            HUART hUART = new HdcUART();
391            if (!hUART) {
392                ret = -1;
393                break;
394            }
395            hSession->hUART = hUART;
396            break;
397        }
398#endif // HDC_SUPPORT_UART
399        default:
400            ret = -1;
401            break;
402    }
403    return ret;
404}
405
406// Avoid unit test when client\server\daemon on the same host, maybe get the same ID value
407uint32_t HdcSessionBase::GetSessionPseudoUid()
408{
409    uint32_t uid = 0;
410    do {
411        uid = Base::GetSecureRandom();
412    } while (AdminSession(OP_QUERY, uid, nullptr) != nullptr);
413    return uid;
414}
415
416// when client 0 to automatic generated,when daemon First place 1 followed by
417HSession HdcSessionBase::MallocSession(bool serverOrDaemon, const ConnType connType, void *classModule,
418                                       uint32_t sessionId)
419{
420#ifdef CONFIG_USE_JEMALLOC_DFX_INIF
421    mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
422    mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
423#endif
424    HSession hSession = new(std::nothrow) HdcSession();
425    if (!hSession) {
426        WRITE_LOG(LOG_FATAL, "MallocSession new hSession failed");
427        return nullptr;
428    }
429    int ret = 0;
430    ++sessionRef;
431    hSession->classInstance = this;
432    hSession->connType = connType;
433    hSession->classModule = classModule;
434    hSession->isDead = false;
435    hSession->sessionId = ((sessionId == 0) ? GetSessionPseudoUid() : sessionId);
436    hSession->serverOrDaemon = serverOrDaemon;
437    hSession->hWorkThread = uv_thread_self();
438    hSession->mapTask = new(std::nothrow) map<uint32_t, HTaskInfo>();
439    if (hSession->mapTask == nullptr) {
440        WRITE_LOG(LOG_FATAL, "MallocSession new hSession->mapTask failed");
441        delete hSession;
442        hSession = nullptr;
443        return nullptr;
444    }
445    hSession->listKey = new(std::nothrow) list<void *>;
446    if (hSession->listKey == nullptr) {
447        WRITE_LOG(LOG_FATAL, "MallocSession new hSession->listKey failed");
448        delete hSession;
449        hSession = nullptr;
450        return nullptr;
451    }
452    uv_loop_init(&hSession->childLoop);
453    hSession->uvHandleRef = 0;
454    // pullup child
455    WRITE_LOG(LOG_INFO, "HdcSessionBase NewSession, sessionId:%u, connType:%d.",
456              hSession->sessionId, hSession->connType);
457    ++hSession->uvHandleRef;
458    Base::CreateSocketPair(hSession->ctrlFd);
459    size_t handleSize = sizeof(uv_poll_t);
460    hSession->pollHandle[STREAM_WORK] = (uv_poll_t *)malloc(handleSize);
461    hSession->pollHandle[STREAM_MAIN] = (uv_poll_t *)malloc(handleSize);
462    uv_poll_t *pollHandleMain = hSession->pollHandle[STREAM_MAIN];
463    if (pollHandleMain == nullptr || hSession->pollHandle[STREAM_WORK] == nullptr) {
464        WRITE_LOG(LOG_FATAL, "MallocSession malloc hSession->pollHandle failed");
465        delete hSession;
466        hSession = nullptr;
467        return nullptr;
468    }
469    uv_poll_init_socket(&loopMain, pollHandleMain, hSession->ctrlFd[STREAM_MAIN]);
470    uv_poll_start(pollHandleMain, UV_READABLE, ReadCtrlFromSession);
471    hSession->pollHandle[STREAM_MAIN]->data = hSession;
472    hSession->pollHandle[STREAM_WORK]->data = hSession;
473    // Activate USB DAEMON's data channel, may not for use
474    uv_tcp_init(&loopMain, &hSession->dataPipe[STREAM_MAIN]);
475    (void)memset_s(&hSession->dataPipe[STREAM_WORK], sizeof(hSession->dataPipe[STREAM_WORK]),
476                   0, sizeof(uv_tcp_t));
477    ++hSession->uvHandleRef;
478    Base::CreateSocketPair(hSession->dataFd);
479    uv_tcp_open(&hSession->dataPipe[STREAM_MAIN], hSession->dataFd[STREAM_MAIN]);
480    hSession->dataPipe[STREAM_MAIN].data = hSession;
481    hSession->dataPipe[STREAM_WORK].data = hSession;
482#ifdef HDC_HOST
483    Base::SetTcpOptions(&hSession->dataPipe[STREAM_MAIN], HOST_SOCKETPAIR_SIZE);
484#else
485    Base::SetTcpOptions(&hSession->dataPipe[STREAM_MAIN]);
486#endif
487    ret = MallocSessionByConnectType(hSession);
488    if (ret) {
489        delete hSession;
490        hSession = nullptr;
491    } else {
492        AdminSession(OP_ADD, hSession->sessionId, hSession);
493    }
494    return hSession;
495}
496
497void HdcSessionBase::FreeSessionByConnectType(HSession hSession)
498{
499    WRITE_LOG(LOG_DEBUG, "FreeSessionByConnectType %s", hSession->ToDebugString().c_str());
500
501    if (hSession->connType == CONN_USB) {
502        // ibusb All context is applied for sub-threaded, so it needs to be destroyed in the subline
503        if (!hSession->hUSB) {
504            return;
505        }
506        HUSB hUSB = hSession->hUSB;
507        if (!hUSB) {
508            return;
509        }
510#ifdef HDC_HOST
511        if (hUSB->devHandle) {
512            libusb_release_interface(hUSB->devHandle, hUSB->interfaceNumber);
513            libusb_close(hUSB->devHandle);
514            hUSB->devHandle = nullptr;
515        }
516#else
517        Base::CloseFd(hUSB->bulkIn);
518        Base::CloseFd(hUSB->bulkOut);
519#endif
520        delete hSession->hUSB;
521        hSession->hUSB = nullptr;
522    }
523#ifdef HDC_SUPPORT_UART
524    if (CONN_SERIAL == hSession->connType) {
525        if (!hSession->hUART) {
526            return;
527        }
528        HUART hUART = hSession->hUART;
529        if (!hUART) {
530            return;
531        }
532        HdcUARTBase *uartBase = (HdcUARTBase *)hSession->classModule;
533        // tell uart session will be free
534        uartBase->StopSession(hSession);
535#ifdef HDC_HOST
536#ifdef HOST_MINGW
537        if (hUART->devUartHandle != INVALID_HANDLE_VALUE) {
538            CloseHandle(hUART->devUartHandle);
539            hUART->devUartHandle = INVALID_HANDLE_VALUE;
540        }
541#elif defined(HOST_LINUX)
542        Base::CloseFd(hUART->devUartHandle);
543#endif // _WIN32
544#endif
545        delete hSession->hUART;
546        hSession->hUART = nullptr;
547    }
548#endif
549}
550
551// work when libuv-handle at struct of HdcSession has all callback finished
552void HdcSessionBase::FreeSessionFinally(uv_idle_t *handle)
553{
554    HSession hSession = (HSession)handle->data;
555    HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance;
556    if (hSession->uvHandleRef > 0) {
557        WRITE_LOG(LOG_INFO, "FreeSessionFinally uvHandleRef:%d sessionId:%u",
558            hSession->uvHandleRef, hSession->sessionId);
559        return;
560    }
561    // Notify Server or Daemon, just UI or display commandline
562    thisClass->NotifyInstanceSessionFree(hSession, true);
563    // all hsession uv handle has been clear
564    thisClass->AdminSession(OP_REMOVE, hSession->sessionId, nullptr);
565    WRITE_LOG(LOG_INFO, "!!!FreeSessionFinally sessionId:%u finish", hSession->sessionId);
566    HdcAuth::FreeKey(!hSession->serverOrDaemon, hSession->listKey);
567    delete hSession;
568    hSession = nullptr;  // fix CodeMars SetNullAfterFree issue
569    Base::TryCloseHandle((const uv_handle_t *)handle, Base::CloseIdleCallback);
570    --thisClass->sessionRef;
571}
572
573// work when child-work thread finish
574void HdcSessionBase::FreeSessionContinue(HSession hSession)
575{
576    auto closeSessionTCPHandle = [](uv_handle_t *handle) -> void {
577        HSession hSession = (HSession)handle->data;
578        --hSession->uvHandleRef;
579        Base::TryCloseHandle((uv_handle_t *)handle);
580        if (handle == reinterpret_cast<uv_handle_t *>(hSession->pollHandle[STREAM_MAIN])) {
581            Base::CloseFd(hSession->ctrlFd[STREAM_MAIN]);
582            Base::CloseFd(hSession->ctrlFd[STREAM_WORK]);
583            free(hSession->pollHandle[STREAM_MAIN]);
584        }
585    };
586    if (hSession->connType == CONN_TCP) {
587        // Turn off TCP to prevent continuing writing
588        Base::TryCloseHandle((uv_handle_t *)&hSession->hWorkTCP, true, closeSessionTCPHandle);
589        Base::CloseFd(hSession->dataFd[STREAM_WORK]);
590    }
591    hSession->availTailIndex = 0;
592    if (hSession->ioBuf) {
593        delete[] hSession->ioBuf;
594        hSession->ioBuf = nullptr;
595    }
596    Base::TryCloseHandle((uv_handle_t *)hSession->pollHandle[STREAM_MAIN], true, closeSessionTCPHandle);
597    Base::TryCloseHandle((uv_handle_t *)&hSession->dataPipe[STREAM_MAIN], true, closeSessionTCPHandle);
598    FreeSessionByConnectType(hSession);
599    // finish
600    Base::IdleUvTask(&loopMain, hSession, FreeSessionFinally);
601}
602
603void HdcSessionBase::FreeSessionOpeate(uv_timer_t *handle)
604{
605    StartTraceScope("HdcSessionBase::FreeSessionOpeate");
606    HSession hSession = (HSession)handle->data;
607#ifdef HDC_HOST
608    if (hSession->hUSB != nullptr
609        && (!hSession->hUSB->hostBulkIn.isShutdown || !hSession->hUSB->hostBulkOut.isShutdown)) {
610        HdcUSBBase *pUSB = ((HdcUSBBase *)hSession->classModule);
611        pUSB->CancelUsbIo(hSession);
612        return;
613    }
614#endif
615    HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance;
616    if (hSession->ref > 0) {
617        WRITE_LOG(LOG_WARN, "FreeSessionOpeate sid:%u ref:%u > 0", hSession->sessionId, uint32_t(hSession->ref));
618        return;
619    }
620    WRITE_LOG(LOG_INFO, "FreeSessionOpeate sid:%u ref:%u", hSession->sessionId, uint32_t(hSession->ref));
621    // wait workthread to free
622    if (hSession->pollHandle[STREAM_WORK]->loop) {
623        auto ctrl = BuildCtrlString(SP_STOP_SESSION, 0, nullptr, 0);
624        Base::SendToPollFd(hSession->ctrlFd[STREAM_MAIN], ctrl.data(), ctrl.size());
625        WRITE_LOG(LOG_INFO, "FreeSessionOpeate, send workthread for free. sessionId:%u", hSession->sessionId);
626        auto callbackCheckFreeSessionContinue = [](uv_timer_t *handle) -> void {
627            HSession hSession = (HSession)handle->data;
628            HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance;
629            if (!hSession->childCleared) {
630                WRITE_LOG(LOG_INFO, "FreeSessionOpeate childCleared:%d sessionId:%u",
631                    hSession->childCleared, hSession->sessionId);
632                return;
633            }
634            Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback);
635            thisClass->FreeSessionContinue(hSession);
636        };
637        Base::TimerUvTask(&thisClass->loopMain, hSession, callbackCheckFreeSessionContinue);
638    } else {
639        thisClass->FreeSessionContinue(hSession);
640    }
641    Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseTimerCallback);
642}
643
644void HdcSessionBase::FreeSession(const uint32_t sessionId)
645{
646    StartTraceScope("HdcSessionBase::FreeSession");
647    Base::AddDeletedSessionId(sessionId);
648    if (threadSessionMain != uv_thread_self()) {
649        PushAsyncMessage(sessionId, ASYNC_FREE_SESSION, nullptr, 0);
650        return;
651    }
652    HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr);
653    WRITE_LOG(LOG_INFO, "Begin to free session, sessionid:%u", sessionId);
654    do {
655        if (!hSession || hSession->isDead) {
656            WRITE_LOG(LOG_WARN, "FreeSession hSession nullptr or isDead sessionId:%u", sessionId);
657            break;
658        }
659        WRITE_LOG(LOG_INFO, "dataFdSend:%llu, dataFdRecv:%llu",
660            uint64_t(hSession->stat.dataSendBytes),
661            uint64_t(hSession->stat.dataRecvBytes));
662        hSession->isDead = true;
663        Base::TimerUvTask(&loopMain, hSession, FreeSessionOpeate);
664        NotifyInstanceSessionFree(hSession, false);
665        WRITE_LOG(LOG_INFO, "FreeSession sessionId:%u ref:%u", hSession->sessionId, uint32_t(hSession->ref));
666    } while (false);
667}
668
669HSession HdcSessionBase::AdminSession(const uint8_t op, const uint32_t sessionId, HSession hInput)
670{
671    HSession hRet = nullptr;
672    switch (op) {
673        case OP_ADD:
674            uv_rwlock_wrlock(&lockMapSession);
675            mapSession[sessionId] = hInput;
676            uv_rwlock_wrunlock(&lockMapSession);
677            break;
678        case OP_REMOVE:
679            uv_rwlock_wrlock(&lockMapSession);
680            mapSession.erase(sessionId);
681            uv_rwlock_wrunlock(&lockMapSession);
682            break;
683        case OP_QUERY:
684            uv_rwlock_rdlock(&lockMapSession);
685            if (mapSession.count(sessionId)) {
686                hRet = mapSession[sessionId];
687            }
688            uv_rwlock_rdunlock(&lockMapSession);
689            break;
690        case OP_QUERY_REF:
691            uv_rwlock_wrlock(&lockMapSession);
692            if (mapSession.count(sessionId)) {
693                hRet = mapSession[sessionId];
694                ++hRet->ref;
695            }
696            uv_rwlock_wrunlock(&lockMapSession);
697            break;
698        case OP_UPDATE:
699            uv_rwlock_wrlock(&lockMapSession);
700            // remove old
701            mapSession.erase(sessionId);
702            mapSession[hInput->sessionId] = hInput;
703            uv_rwlock_wrunlock(&lockMapSession);
704            break;
705        case OP_VOTE_RESET:
706            if (mapSession.count(sessionId) == 0) {
707                break;
708            }
709            bool needReset;
710            if (serverOrDaemon) {
711                uv_rwlock_wrlock(&lockMapSession);
712                hRet = mapSession[sessionId];
713                hRet->voteReset = true;
714                needReset = true;
715                for (auto &kv : mapSession) {
716                    if (sessionId == kv.first) {
717                        continue;
718                    }
719                    WRITE_LOG(LOG_DEBUG, "session:%u vote reset, session %u is %s",
720                              sessionId, kv.first, kv.second->voteReset ? "YES" : "NO");
721                    if (!kv.second->voteReset) {
722                        needReset = false;
723                    }
724                }
725                uv_rwlock_wrunlock(&lockMapSession);
726            } else {
727                needReset = true;
728            }
729            if (needReset) {
730                WRITE_LOG(LOG_FATAL, "!! session:%u vote reset, passed unanimously !!", sessionId);
731                abort();
732            }
733            break;
734        default:
735            break;
736    }
737    return hRet;
738}
739
740void HdcSessionBase::DumpTasksInfo(map<uint32_t, HTaskInfo> &mapTask)
741{
742    int idx = 1;
743    for (auto t : mapTask) {
744        HTaskInfo ti = t.second;
745        WRITE_LOG(LOG_WARN, "%d: channelId: %lu, type: %d, closeRetry: %d\n",
746                  idx++, ti->channelId, ti->taskType, ti->closeRetryCount);
747    }
748}
749
750// All in the corresponding sub-thread, no need locks
751HTaskInfo HdcSessionBase::AdminTask(const uint8_t op, HSession hSession, const uint32_t channelId, HTaskInfo hInput)
752{
753    HTaskInfo hRet = nullptr;
754    map<uint32_t, HTaskInfo> &mapTask = *hSession->mapTask;
755
756    switch (op) {
757        case OP_ADD:
758            hRet = mapTask[channelId];
759            if (hRet != nullptr) {
760                delete hRet;
761            }
762            mapTask[channelId] = hInput;
763            hRet = hInput;
764
765            WRITE_LOG(LOG_WARN, "AdminTask add session %u, channelId %u, mapTask size: %zu",
766                      hSession->sessionId, channelId, mapTask.size());
767
768            break;
769        case OP_REMOVE:
770            mapTask.erase(channelId);
771            WRITE_LOG(LOG_DEBUG, "AdminTask rm session %u, channelId %u, mapTask size: %zu",
772                      hSession->sessionId, channelId, mapTask.size());
773            break;
774        case OP_QUERY:
775            if (mapTask.count(channelId)) {
776                hRet = mapTask[channelId];
777            }
778            break;
779        case OP_VOTE_RESET:
780            AdminSession(op, hSession->sessionId, nullptr);
781            break;
782        default:
783            break;
784    }
785    return hRet;
786}
787
788int HdcSessionBase::SendByProtocol(HSession hSession, uint8_t *bufPtr, const int bufLen, bool echo)
789{
790    StartTraceScope("HdcSessionBase::SendByProtocol");
791    if (hSession->isDead) {
792        delete[] bufPtr;
793        WRITE_LOG(LOG_WARN, "SendByProtocol session dead error");
794        return ERR_SESSION_NOFOUND;
795    }
796    int ret = 0;
797    switch (hSession->connType) {
798        case CONN_TCP: {
799            HdcTCPBase *pTCP = ((HdcTCPBase *)hSession->classModule);
800            if (echo && !hSession->serverOrDaemon) {
801                ret = pTCP->WriteUvTcpFd(&hSession->hChildWorkTCP, bufPtr, bufLen);
802            } else {
803                if (hSession->hWorkThread == uv_thread_self()) {
804                    ret = pTCP->WriteUvTcpFd(&hSession->hWorkTCP, bufPtr, bufLen);
805                } else {
806                    ret = pTCP->WriteUvTcpFd(&hSession->hChildWorkTCP, bufPtr, bufLen);
807                }
808            }
809            break;
810        }
811        case CONN_USB: {
812            HdcUSBBase *pUSB = ((HdcUSBBase *)hSession->classModule);
813            ret = pUSB->SendUSBBlock(hSession, bufPtr, bufLen);
814            delete[] bufPtr;
815            break;
816        }
817#ifdef HDC_SUPPORT_UART
818        case CONN_SERIAL: {
819            HdcUARTBase *pUART = ((HdcUARTBase *)hSession->classModule);
820            ret = pUART->SendUARTData(hSession, bufPtr, bufLen);
821            delete[] bufPtr;
822            break;
823        }
824#endif
825        default:
826            break;
827    }
828    return ret;
829}
830
831int HdcSessionBase::Send(const uint32_t sessionId, const uint32_t channelId, const uint16_t commandFlag,
832                         const uint8_t *data, const int dataSize)
833{
834    StartTraceScope("HdcSessionBase::Send");
835    HSession hSession = AdminSession(OP_QUERY, sessionId, nullptr);
836    if (!hSession) {
837        WRITE_LOG(LOG_WARN, "Send to offline device, drop it, sessionId:%u", sessionId);
838        return ERR_SESSION_NOFOUND;
839    }
840    PayloadProtect protectBuf;  // noneed convert to big-endian
841    protectBuf.channelId = channelId;
842    protectBuf.commandFlag = commandFlag;
843    protectBuf.checkSum = (ENABLE_IO_CHECKSUM && dataSize > 0) ? Base::CalcCheckSum(data, dataSize) : 0;
844    protectBuf.vCode = payloadProtectStaticVcode;
845    string s = SerialStruct::SerializeToString(protectBuf);
846    // reserve for encrypt here
847    // xx-encrypt
848
849    PayloadHead payloadHead = {};  // need convert to big-endian
850    payloadHead.flag[0] = PACKET_FLAG.at(0);
851    payloadHead.flag[1] = PACKET_FLAG.at(1);
852    payloadHead.protocolVer = VER_PROTOCOL;
853    payloadHead.headSize = htons(s.size());
854    payloadHead.dataSize = htonl(dataSize);
855    int finalBufSize = sizeof(PayloadHead) + s.size() + dataSize;
856    uint8_t *finayBuf = new(std::nothrow) uint8_t[finalBufSize]();
857    if (finayBuf == nullptr) {
858        WRITE_LOG(LOG_WARN, "send allocmem err");
859        return ERR_BUF_ALLOC;
860    }
861    bool bufRet = false;
862    do {
863        if (memcpy_s(finayBuf, sizeof(PayloadHead), reinterpret_cast<uint8_t *>(&payloadHead), sizeof(PayloadHead))) {
864            WRITE_LOG(LOG_WARN, "send copyhead err for dataSize:%d", dataSize);
865            break;
866        }
867        if (memcpy_s(finayBuf + sizeof(PayloadHead), s.size(),
868                     reinterpret_cast<uint8_t *>(const_cast<char *>(s.c_str())), s.size())) {
869            WRITE_LOG(LOG_WARN, "send copyProtbuf err for dataSize:%d", dataSize);
870            break;
871        }
872        if (dataSize > 0 && memcpy_s(finayBuf + sizeof(PayloadHead) + s.size(), dataSize, data, dataSize)) {
873            WRITE_LOG(LOG_WARN, "send copyDatabuf err for dataSize:%d", dataSize);
874            break;
875        }
876        bufRet = true;
877    } while (false);
878    if (!bufRet) {
879        delete[] finayBuf;
880        WRITE_LOG(LOG_WARN, "send copywholedata err for dataSize:%d", dataSize);
881        return ERR_BUF_COPY;
882    }
883    if (CMD_KERNEL_ECHO == commandFlag) {
884        return SendByProtocol(hSession, finayBuf, finalBufSize, true);
885    } else {
886        return SendByProtocol(hSession, finayBuf, finalBufSize);
887    }
888}
889
890int HdcSessionBase::DecryptPayload(HSession hSession, PayloadHead *payloadHeadBe, uint8_t *encBuf)
891{
892    StartTraceScope("HdcSessionBase::DecryptPayload");
893    PayloadProtect protectBuf = {};
894    uint16_t headSize = ntohs(payloadHeadBe->headSize);
895    int dataSize = ntohl(payloadHeadBe->dataSize);
896    string encString(reinterpret_cast<char *>(encBuf), headSize);
897    SerialStruct::ParseFromString(protectBuf, encString);
898    if (protectBuf.vCode != payloadProtectStaticVcode) {
899        WRITE_LOG(LOG_FATAL, "Session recv static vcode failed");
900        return ERR_BUF_CHECK;
901    }
902    uint8_t *data = encBuf + headSize;
903    if (ENABLE_IO_CHECKSUM && protectBuf.checkSum != 0 && (protectBuf.checkSum != Base::CalcCheckSum(data, dataSize))) {
904        WRITE_LOG(LOG_FATAL, "Session recv CalcCheckSum failed");
905        return ERR_BUF_CHECK;
906    }
907    if (!FetchCommand(hSession, protectBuf.channelId, protectBuf.commandFlag, data, dataSize)) {
908        WRITE_LOG(LOG_WARN, "FetchCommand failed: channelId %x commandFlag %x",
909                  protectBuf.channelId, protectBuf.commandFlag);
910        return ERR_GENERIC;
911    }
912    return RET_SUCCESS;
913}
914
915int HdcSessionBase::OnRead(HSession hSession, uint8_t *bufPtr, const int bufLen)
916{
917    int ret = ERR_GENERIC;
918    StartTraceScope("HdcSessionBase::OnRead");
919    if (memcmp(bufPtr, PACKET_FLAG.c_str(), PACKET_FLAG.size())) {
920        WRITE_LOG(LOG_FATAL, "PACKET_FLAG incorrect %x %x", bufPtr[0], bufPtr[1]);
921        return ERR_BUF_CHECK;
922    }
923    struct PayloadHead *payloadHead = reinterpret_cast<struct PayloadHead *>(bufPtr);
924    // to prevent integer overflow caused by the add operation of two input num
925    uint64_t payloadHeadSize = static_cast<uint64_t>(ntohl(payloadHead->dataSize)) +
926        static_cast<uint64_t>(ntohs(payloadHead->headSize));
927    int packetHeadSize = sizeof(struct PayloadHead);
928    if (payloadHeadSize == 0 || payloadHeadSize > static_cast<uint64_t>(HDC_BUF_MAX_BYTES)) {
929        WRITE_LOG(LOG_FATAL, "Packet size incorrect");
930        return ERR_BUF_CHECK;
931    }
932
933    // 0 < payloadHeadSize < HDC_BUF_MAX_BYTES
934    int tobeReadLen = static_cast<int>(payloadHeadSize);
935    if (bufLen - packetHeadSize < tobeReadLen) {
936        return 0;
937    }
938    if (DecryptPayload(hSession, payloadHead, bufPtr + packetHeadSize)) {
939        WRITE_LOG(LOG_WARN, "decrypt plhead error");
940        return ERR_BUF_CHECK;
941    }
942    ret = packetHeadSize + tobeReadLen;
943    return ret;
944}
945
946// Returns <0 error;> 0 receives the number of bytes; 0 untreated
947int HdcSessionBase::FetchIOBuf(HSession hSession, uint8_t *ioBuf, int read)
948{
949    HdcSessionBase *ptrConnect = (HdcSessionBase *)hSession->classInstance;
950    int indexBuf = 0;
951    int childRet = 0;
952    StartTraceScope("HdcSessionBase::FetchIOBuf");
953    if (read < 0) {
954        constexpr int bufSize = 1024;
955        char buf[bufSize] = { 0 };
956        uv_strerror_r(read, buf, bufSize);
957        WRITE_LOG(LOG_FATAL, "FetchIOBuf read io failed,%s", buf);
958        return ERR_IO_FAIL;
959    }
960    hSession->stat.dataRecvBytes += read;
961    hSession->availTailIndex += read;
962    while (!hSession->isDead && hSession->availTailIndex > static_cast<int>(sizeof(PayloadHead))) {
963        childRet = ptrConnect->OnRead(hSession, ioBuf + indexBuf, hSession->availTailIndex);
964        if (childRet > 0) {
965            hSession->availTailIndex -= childRet;
966            indexBuf += childRet;
967        } else if (childRet == 0) {
968            // Not enough a IO
969            break;
970        } else {                           // <0
971            WRITE_LOG(LOG_FATAL, "FetchIOBuf error childRet:%d sessionId:%u", childRet, hSession->sessionId);
972            hSession->availTailIndex = 0;  // Preventing malicious data packages
973            indexBuf = ERR_BUF_SIZE;
974            break;
975        }
976        // It may be multi-time IO to merge in a BUF, need to loop processing
977    }
978    if (indexBuf > 0 && hSession->availTailIndex > 0) {
979        if (memmove_s(hSession->ioBuf, hSession->bufSize, hSession->ioBuf + indexBuf, hSession->availTailIndex)
980            != EOK) {
981            return ERR_BUF_COPY;
982        };
983        uint8_t *bufToZero = reinterpret_cast<uint8_t *>(hSession->ioBuf + hSession->availTailIndex);
984        Base::ZeroBuf(bufToZero, hSession->bufSize - hSession->availTailIndex);
985    }
986    return indexBuf;
987}
988
989void HdcSessionBase::AllocCallback(uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf)
990{
991    HSession context = (HSession)handle->data;
992    Base::ReallocBuf(&context->ioBuf, &context->bufSize, HDC_SOCKETPAIR_SIZE);
993    buf->base = (char *)context->ioBuf + context->availTailIndex;
994    int size = context->bufSize - context->availTailIndex;
995    buf->len = std::min(size, static_cast<int>(sizeWanted));
996}
997
998void HdcSessionBase::FinishWriteSessionTCP(uv_write_t *req, int status)
999{
1000    HSession hSession = (HSession)req->handle->data;
1001    --hSession->ref;
1002    HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance;
1003    if (status < 0) {
1004        WRITE_LOG(LOG_WARN, "FinishWriteSessionTCP status:%d sessionId:%u isDead:%d ref:%u",
1005            status, hSession->sessionId, hSession->isDead, uint32_t(hSession->ref));
1006        Base::TryCloseHandle((uv_handle_t *)req->handle);
1007        if (!hSession->isDead && !hSession->ref) {
1008            WRITE_LOG(LOG_DEBUG, "FinishWriteSessionTCP freesession :%u", hSession->sessionId);
1009            thisClass->FreeSession(hSession->sessionId);
1010        }
1011    }
1012    delete[]((uint8_t *)req->data);
1013    delete req;
1014}
1015
1016bool HdcSessionBase::DispatchSessionThreadCommand(HSession hSession, const uint8_t *baseBuf,
1017                                                  const int bytesIO)
1018{
1019    bool ret = true;
1020    uint8_t flag = *const_cast<uint8_t *>(baseBuf);
1021
1022    switch (flag) {
1023        case SP_JDWP_NEWFD:
1024        case SP_ARK_NEWFD: {
1025            JdwpNewFileDescriptor(baseBuf, bytesIO);
1026            break;
1027        }
1028        default:
1029            WRITE_LOG(LOG_WARN, "Not support session command");
1030            break;
1031    }
1032    return ret;
1033}
1034
1035void HdcSessionBase::ReadCtrlFromSession(uv_poll_t *poll, int status, int events)
1036{
1037    HSession hSession = (HSession)poll->data;
1038    HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance;
1039    const int size = Base::GetMaxBufSizeStable();
1040    char *buf = reinterpret_cast<char *>(new uint8_t[size]());
1041    ssize_t nread = Base::ReadFromFd(hSession->ctrlFd[STREAM_MAIN], buf, size);
1042    while (true) {
1043        if (nread < 0) {
1044            constexpr int bufSize = 1024;
1045            char buffer[bufSize] = { 0 };
1046            uv_strerror_r(static_cast<int>(nread), buffer, bufSize);
1047            WRITE_LOG(LOG_WARN, "ReadCtrlFromSession failed,%s", buffer);
1048            uv_poll_stop(poll);
1049            break;
1050        }
1051        if (nread == 0) {
1052            WRITE_LOG(LOG_FATAL, "ReadCtrlFromSession read data zero byte");
1053            break;
1054        }
1055        // only one command, no need to split command from stream
1056        // if add more commands, consider the format command
1057        hSessionBase->DispatchSessionThreadCommand(hSession, reinterpret_cast<uint8_t *>(buf), nread);
1058        break;
1059    }
1060    delete[] buf;
1061}
1062
1063void HdcSessionBase::WorkThreadInitSession(HSession hSession, SessionHandShake &handshake)
1064{
1065    handshake.banner = HANDSHAKE_MESSAGE;
1066    handshake.sessionId = hSession->sessionId;
1067    handshake.connectKey = hSession->connectKey;
1068    if (!hSession->isCheck) {
1069        handshake.version = Base::GetVersion() + HDC_MSG_HASH;
1070        WRITE_LOG(LOG_INFO, "set version = %s", handshake.version.c_str());
1071    }
1072    handshake.authType = AUTH_NONE;
1073    // told daemon, we support RSA_3072_SHA512 auth
1074    Base::TlvAppend(handshake.buf, TAG_AUTH_TYPE, std::to_string(AuthVerifyType::RSA_3072_SHA512));
1075}
1076
1077bool HdcSessionBase::WorkThreadStartSession(HSession hSession)
1078{
1079    bool regOK = false;
1080    int childRet = 0;
1081    if (hSession->connType == CONN_TCP) {
1082        HdcTCPBase *pTCPBase = (HdcTCPBase *)hSession->classModule;
1083        hSession->hChildWorkTCP.data = hSession;
1084        if (uv_tcp_init(&hSession->childLoop, &hSession->hChildWorkTCP) < 0) {
1085            WRITE_LOG(LOG_WARN, "HdcSessionBase SessionCtrl failed 1");
1086            return false;
1087        }
1088        if ((childRet = uv_tcp_open(&hSession->hChildWorkTCP, hSession->fdChildWorkTCP)) < 0) {
1089            constexpr int bufSize = 1024;
1090            char buf[bufSize] = { 0 };
1091            uv_strerror_r(childRet, buf, bufSize);
1092            WRITE_LOG(LOG_WARN, "SessionCtrl failed 2,fd:%d,str:%s", hSession->fdChildWorkTCP, buf);
1093            return false;
1094        }
1095        Base::SetTcpOptions((uv_tcp_t *)&hSession->hChildWorkTCP);
1096        uv_read_start((uv_stream_t *)&hSession->hChildWorkTCP, AllocCallback, pTCPBase->ReadStream);
1097        regOK = true;
1098#ifdef HDC_SUPPORT_UART
1099    } else if (hSession->connType == CONN_SERIAL) { // UART
1100        HdcUARTBase *pUARTBase = (HdcUARTBase *)hSession->classModule;
1101        WRITE_LOG(LOG_DEBUG, "UART ReadyForWorkThread");
1102        regOK = pUARTBase->ReadyForWorkThread(hSession);
1103#endif
1104    } else {  // USB
1105        HdcUSBBase *pUSBBase = (HdcUSBBase *)hSession->classModule;
1106        WRITE_LOG(LOG_DEBUG, "USB ReadyForWorkThread");
1107        regOK = pUSBBase->ReadyForWorkThread(hSession);
1108    }
1109
1110    if (regOK && hSession->serverOrDaemon) {
1111        // session handshake step1
1112        SessionHandShake handshake = {};
1113        WorkThreadInitSession(hSession, handshake);
1114        string hs = SerialStruct::SerializeToString(handshake);
1115#ifdef HDC_SUPPORT_UART
1116        WRITE_LOG(LOG_DEBUG, "WorkThreadStartSession session %u auth %u send handshake hs: %s",
1117                  hSession->sessionId, handshake.authType, hs.c_str());
1118#endif
1119        Send(hSession->sessionId, 0, CMD_KERNEL_HANDSHAKE,
1120             reinterpret_cast<uint8_t *>(const_cast<char *>(hs.c_str())), hs.size());
1121    }
1122    return regOK;
1123}
1124
1125vector<uint8_t> HdcSessionBase::BuildCtrlString(InnerCtrlCommand command, uint32_t channelId, uint8_t *data,
1126                                                int dataSize)
1127{
1128    vector<uint8_t> ret;
1129    while (true) {
1130        if (dataSize > BUF_SIZE_MICRO) {
1131            WRITE_LOG(LOG_WARN, "BuildCtrlString dataSize:%d", dataSize);
1132            break;
1133        }
1134        CtrlStruct ctrl = {};
1135        ctrl.command = command;
1136        ctrl.channelId = channelId;
1137        ctrl.dataSize = dataSize;
1138        if (dataSize > 0 && data != nullptr && memcpy_s(ctrl.data, sizeof(ctrl.data), data, dataSize) != EOK) {
1139            break;
1140        }
1141        uint8_t *buf = reinterpret_cast<uint8_t *>(&ctrl);
1142        ret.insert(ret.end(), buf, buf + sizeof(CtrlStruct));
1143        break;
1144    }
1145    return ret;
1146}
1147
1148bool HdcSessionBase::DispatchMainThreadCommand(HSession hSession, const CtrlStruct *ctrl)
1149{
1150    bool ret = true;
1151    uint32_t channelId = ctrl->channelId;  // if send not set, it is zero
1152    switch (ctrl->command) {
1153        case SP_START_SESSION: {
1154            WRITE_LOG(LOG_WARN, "Dispatch MainThreadCommand  START_SESSION sessionId:%u instance:%s",
1155                      hSession->sessionId, hSession->serverOrDaemon ? "server" : "daemon");
1156            ret = WorkThreadStartSession(hSession);
1157            break;
1158        }
1159        case SP_STOP_SESSION: {
1160            WRITE_LOG(LOG_WARN, "Dispatch MainThreadCommand STOP_SESSION sessionId:%u", hSession->sessionId);
1161            auto closeSessionChildThreadTCPHandle = [](uv_handle_t *handle) -> void {
1162                HSession hSession = (HSession)handle->data;
1163                Base::TryCloseHandle((uv_handle_t *)handle);
1164                if (handle == (uv_handle_t *)hSession->pollHandle[STREAM_WORK]) {
1165                    free(hSession->pollHandle[STREAM_WORK]);
1166                }
1167                if (--hSession->uvChildRef == 0) {
1168                    uv_stop(&hSession->childLoop);
1169                };
1170            };
1171            constexpr int uvChildRefOffset = 2;
1172            hSession->uvChildRef += uvChildRefOffset;
1173            if (hSession->connType == CONN_TCP && hSession->hChildWorkTCP.loop) {  // maybe not use it
1174                ++hSession->uvChildRef;
1175                Base::TryCloseHandle((uv_handle_t *)&hSession->hChildWorkTCP, true, closeSessionChildThreadTCPHandle);
1176            }
1177            Base::TryCloseHandle((uv_handle_t *)hSession->pollHandle[STREAM_WORK], true,
1178                                 closeSessionChildThreadTCPHandle);
1179            Base::TryCloseHandle((uv_handle_t *)&hSession->dataPipe[STREAM_WORK], true,
1180                                 closeSessionChildThreadTCPHandle);
1181            break;
1182        }
1183        case SP_ATTACH_CHANNEL: {
1184            if (!serverOrDaemon) {
1185                break;  // Only Server has this feature
1186            }
1187            AttachChannel(hSession, channelId);
1188            break;
1189        }
1190        case SP_DEATCH_CHANNEL: {
1191            if (!serverOrDaemon) {
1192                break;  // Only Server has this feature
1193            }
1194            DeatchChannel(hSession, channelId);
1195            break;
1196        }
1197        default:
1198            WRITE_LOG(LOG_WARN, "Not support main command");
1199            ret = false;
1200            break;
1201    }
1202    return ret;
1203}
1204
1205// Several bytes of control instructions, generally do not stick
1206void HdcSessionBase::ReadCtrlFromMain(uv_poll_t *poll, int status, int events)
1207{
1208    HSession hSession = (HSession)poll->data;
1209    HdcSessionBase *hSessionBase = (HdcSessionBase *)hSession->classInstance;
1210    int formatCommandSize = sizeof(CtrlStruct);
1211    int index = 0;
1212    const int size = Base::GetMaxBufSizeStable();
1213    char *buf = reinterpret_cast<char *>(new uint8_t[size]());
1214    ssize_t nread = Base::ReadFromFd(hSession->ctrlFd[STREAM_WORK], buf, size);
1215    while (true) {
1216        if (nread < 0) {
1217            constexpr int bufSize = 1024;
1218            char buffer[bufSize] = { 0 };
1219            uv_strerror_r(static_cast<int>(nread), buffer, bufSize);
1220            WRITE_LOG(LOG_WARN, "SessionCtrl failed,%s", buffer);
1221            break;
1222        }
1223        if (nread % formatCommandSize != 0) {
1224            WRITE_LOG(LOG_FATAL, "ReadCtrlFromMain size failed, nread == %d", nread);
1225            break;
1226        }
1227        CtrlStruct *ctrl = reinterpret_cast<CtrlStruct *>(buf + index);
1228        if (!hSessionBase->DispatchMainThreadCommand(hSession, ctrl)) {
1229            WRITE_LOG(LOG_FATAL, "ReadCtrlFromMain failed sessionId:%u channelId:%u command:%u",
1230                      hSession->sessionId, ctrl->channelId, ctrl->command);
1231            break;
1232        }
1233        index += sizeof(CtrlStruct);
1234        if (index >= nread) {
1235            break;
1236        }
1237    }
1238    delete[] buf;
1239}
1240
1241void HdcSessionBase::ReChildLoopForSessionClear(HSession hSession)
1242{
1243    // Restart loop close task
1244    ClearOwnTasks(hSession, 0);
1245    WRITE_LOG(LOG_INFO, "ReChildLoopForSessionClear sessionId:%u", hSession->sessionId);
1246    auto clearTaskForSessionFinish = [](uv_timer_t *handle) -> void {
1247        HSession hSession = (HSession)handle->data;
1248        for (auto v : *hSession->mapTask) {
1249            HTaskInfo hTask = (HTaskInfo)v.second;
1250            uint8_t level;
1251            if (hTask->closeRetryCount < GLOBAL_TIMEOUT / 2) {
1252                level = LOG_DEBUG;
1253            } else {
1254                level = LOG_WARN;
1255            }
1256            WRITE_LOG(level, "wait task free retry %d/%d, channelId:%u, sessionId:%u",
1257                      hTask->closeRetryCount, GLOBAL_TIMEOUT, hTask->channelId, hTask->sessionId);
1258            if (hTask->closeRetryCount++ >= GLOBAL_TIMEOUT) {
1259                HdcSessionBase *thisClass = (HdcSessionBase *)hTask->ownerSessionClass;
1260                hSession = thisClass->AdminSession(OP_QUERY, hTask->sessionId, nullptr);
1261                thisClass->AdminTask(OP_VOTE_RESET, hSession, hTask->channelId, nullptr);
1262            }
1263            if (!hTask->taskFree)
1264                return;
1265        }
1266        // all task has been free
1267        uv_close((uv_handle_t *)handle, Base::CloseTimerCallback);
1268        uv_stop(&hSession->childLoop);  // stop ReChildLoopForSessionClear pendding
1269    };
1270    Base::TimerUvTask(
1271        &hSession->childLoop, hSession, clearTaskForSessionFinish, (GLOBAL_TIMEOUT * TIME_BASE) / UV_DEFAULT_INTERVAL);
1272    uv_run(&hSession->childLoop, UV_RUN_DEFAULT);
1273    // clear
1274    Base::TryCloseChildLoop(&hSession->childLoop, "Session childUV");
1275}
1276
1277void HdcSessionBase::SessionWorkThread(uv_work_t *arg)
1278{
1279    HSession hSession = (HSession)arg->data;
1280    HdcSessionBase *thisClass = (HdcSessionBase *)hSession->classInstance;
1281    hSession->hWorkChildThread = uv_thread_self();
1282
1283    uv_poll_t *pollHandle = hSession->pollHandle[STREAM_WORK];
1284    pollHandle->data = hSession;
1285    uv_poll_init_socket(&hSession->childLoop, pollHandle, hSession->ctrlFd[STREAM_WORK]);
1286    uv_poll_start(pollHandle, UV_READABLE, ReadCtrlFromMain);
1287    WRITE_LOG(LOG_DEBUG, "!!!Workthread run begin, sessionId:%u instance:%s", hSession->sessionId,
1288              thisClass->serverOrDaemon ? "server" : "daemon");
1289    uv_run(&hSession->childLoop, UV_RUN_DEFAULT);  // work pendding
1290    WRITE_LOG(LOG_DEBUG, "!!!Workthread run again, sessionId:%u", hSession->sessionId);
1291    // main loop has exit
1292    thisClass->ReChildLoopForSessionClear(hSession);  // work pending again
1293    hSession->childCleared = true;
1294    WRITE_LOG(LOG_WARN, "!!!Workthread run finish, sessionId:%u", hSession->sessionId);
1295}
1296
1297// clang-format off
1298void HdcSessionBase::LogMsg(const uint32_t sessionId, const uint32_t channelId,
1299                            MessageLevel level, const char *msg, ...)
1300// clang-format on
1301{
1302    va_list vaArgs;
1303    va_start(vaArgs, msg);
1304    string log = Base::StringFormat(msg, vaArgs);
1305    va_end(vaArgs);
1306    vector<uint8_t> buf;
1307    buf.push_back(level);
1308    buf.insert(buf.end(), log.c_str(), log.c_str() + log.size());
1309    ServerCommand(sessionId, channelId, CMD_KERNEL_ECHO, buf.data(), buf.size());
1310}
1311
1312bool HdcSessionBase::NeedNewTaskInfo(const uint16_t command, bool &masterTask)
1313{
1314    // referer from HdcServerForClient::DoCommandRemote
1315    bool ret = false;
1316    bool taskMasterInit = false;
1317    masterTask = false;
1318    switch (command) {
1319        case CMD_FILE_INIT:
1320        case CMD_FLASHD_FLASH_INIT:
1321        case CMD_FLASHD_UPDATE_INIT:
1322        case CMD_FLASHD_ERASE:
1323        case CMD_FLASHD_FORMAT:
1324        case CMD_FORWARD_INIT:
1325        case CMD_APP_INIT:
1326        case CMD_APP_UNINSTALL:
1327        case CMD_APP_SIDELOAD:
1328            taskMasterInit = true;
1329            break;
1330        default:
1331            break;
1332    }
1333    if (!serverOrDaemon
1334        && (command == CMD_SHELL_INIT || (command > CMD_UNITY_COMMAND_HEAD && command < CMD_UNITY_COMMAND_TAIL))) {
1335        // daemon's single side command
1336        ret = true;
1337    } else if (command == CMD_KERNEL_WAKEUP_SLAVETASK) {
1338        // slave tasks
1339        ret = true;
1340    } else if (command == CMD_UNITY_BUGREPORT_INIT) {
1341        ret = true;
1342    } else if (taskMasterInit) {
1343        // task init command
1344        masterTask = true;
1345        ret = true;
1346    }
1347    return ret;
1348}
1349// Heavy and time-consuming work was putted in the new thread to do, and does
1350// not occupy the main thread
1351bool HdcSessionBase::DispatchTaskData(HSession hSession, const uint32_t channelId, const uint16_t command,
1352                                      uint8_t *payload, int payloadSize)
1353{
1354    StartTraceScope("HdcSessionBase::DispatchTaskData");
1355    bool ret = true;
1356    HTaskInfo hTaskInfo = nullptr;
1357    bool masterTask = false;
1358    while (true) {
1359        // Some basic commands do not have a local task constructor. example: Interactive shell, some uinty commands
1360        if (NeedNewTaskInfo(command, masterTask)) {
1361            WRITE_LOG(LOG_DEBUG, "New HTaskInfo channelId:%u command:%u", channelId, command);
1362            hTaskInfo = new(std::nothrow) TaskInformation();
1363            if (hTaskInfo == nullptr) {
1364                WRITE_LOG(LOG_FATAL, "DispatchTaskData new hTaskInfo failed");
1365                break;
1366            }
1367            hTaskInfo->channelId = channelId;
1368            hTaskInfo->sessionId = hSession->sessionId;
1369            hTaskInfo->runLoop = &hSession->childLoop;
1370            hTaskInfo->serverOrDaemon = serverOrDaemon;
1371            hTaskInfo->masterSlave = masterTask;
1372            hTaskInfo->closeRetryCount = 0;
1373            hTaskInfo->channelTask = false;
1374            hTaskInfo->isCleared = false;
1375
1376            int addTaskRetry = 3; // try 3 time
1377            while (addTaskRetry > 0) {
1378                if (AdminTask(OP_ADD, hSession, channelId, hTaskInfo)) {
1379                    break;
1380                }
1381                sleep(1);
1382                --addTaskRetry;
1383            }
1384
1385            if (addTaskRetry == 0) {
1386#ifndef HDC_HOST
1387                LogMsg(hTaskInfo->sessionId, hTaskInfo->channelId,
1388                       MSG_FAIL, "hdc thread pool busy, may cause reset later");
1389#endif
1390                delete hTaskInfo;
1391                hTaskInfo = nullptr;
1392                ret = false;
1393                break;
1394            }
1395        } else {
1396            hTaskInfo = AdminTask(OP_QUERY, hSession, channelId, nullptr);
1397        }
1398        if (!hTaskInfo || hTaskInfo->taskStop || hTaskInfo->taskFree) {
1399            WRITE_LOG(LOG_ALL, "Dead HTaskInfo, ignore, channelId:%u command:%u", channelId, command);
1400            break;
1401        }
1402        ret = RedirectToTask(hTaskInfo, hSession, channelId, command, payload, payloadSize);
1403        break;
1404    }
1405    return ret;
1406}
1407
1408void HdcSessionBase::PostStopInstanceMessage(bool restart)
1409{
1410    PushAsyncMessage(0, ASYNC_STOP_MAINLOOP, nullptr, 0);
1411    WRITE_LOG(LOG_DEBUG, "StopDaemon has sended restart %d", restart);
1412    wantRestart = restart;
1413}
1414}  // namespace Hdc
1415