diff --git a/src/common/channel.cpp b/src/common/channel.cpp index 09b2854d3e75b13ac80d55b9edbe1d84bd27045e..5499effefde4d3c7f912c24c67acdb51593c67bc 100644 --- a/src/common/channel.cpp +++ b/src/common/channel.cpp @@ -124,6 +124,10 @@ void HdcChannelBase::ReadStream(uv_stream_t *tcp, ssize_t nread, const uv_buf_t if (nread == UV_ENOBUFS) { WRITE_LOG(LOG_FATAL, "ReadStream nobufs channelId:%u", channelId); + hChannel->isSuccess = false; + char buffer[BUF_SIZE_DEFAULT] = { 0 }; + uv_strerror_r(nread, buffer, BUF_SIZE_DEFAULT); + hChannel->faultInfo += buffer; return; } else if (nread == 0) { // maybe just after accept, second client req @@ -135,6 +139,10 @@ void HdcChannelBase::ReadStream(uv_stream_t *tcp, ssize_t nread, const uv_buf_t char buffer[bufSize] = { 0 }; uv_err_name_r(nread, buffer, bufSize); WRITE_LOG(LOG_DEBUG, "ReadStream channelId:%u failed:%s", channelId, buffer); + + hChannel->isSuccess = false; + hChannel->faultInfo += buffer; + needExit = true; goto Finish; } else { @@ -144,6 +152,8 @@ void HdcChannelBase::ReadStream(uv_stream_t *tcp, ssize_t nread, const uv_buf_t size = ntohl(*reinterpret_cast(hChannel->ioBuf + indexBuf)); // big endian if (size <= 0 || static_cast(size) > HDC_BUF_MAX_BYTES) { WRITE_LOG(LOG_FATAL, "ReadStream size:%d channelId:%u", size, channelId); + hChannel->isSuccess = false; + hChannel->faultInfo += "parse error: size field of the package header is too big"; needExit = true; break; } @@ -175,6 +185,8 @@ Finish: if (needExit) { thisClass->FreeChannel(hChannel->channelId); WRITE_LOG(LOG_DEBUG, "Read Stream needExit, FreeChannel finish channelId:%u", channelId); + } else { + hChannel->isSuccess = hChannel->faultInfo.size() == 0; } } @@ -455,6 +467,10 @@ void HdcChannelBase::FreeChannelFinally(uv_idle_t *handle) return; } thisClass->NotifyInstanceChannelFree(hChannel); + hChannel->endTime = Base::GetRuntimeMSec(); + if (hChannel->serverOrClient) { + thisClass->AdminChannel(OP_PRINT, -1, nullptr); + } thisClass->AdminChannel(OP_REMOVE, hChannel->channelId, nullptr); if (!hChannel->serverOrClient) { @@ -557,6 +573,17 @@ HChannel HdcChannelBase::AdminChannel(const uint8_t op, const uint32_t channelId { HChannel hRet = nullptr; switch (op) { + case OP_PRINT: +#ifdef HDC_HOST + uv_rwlock_rdlock(&lockMapChannel); + for (auto v : mapChannel) { + HChannel hChannel = (HChannel)v.second; + auto str = hChannel->ToDisplayChannelStr(); + WRITE_LOG(LOG_INFO, "%s", str.c_str()); + } + uv_rwlock_rdunlock(&lockMapChannel); +#endif + break; case OP_ADD: uv_rwlock_wrlock(&lockMapChannel); mapChannel[channelId] = hInput; diff --git a/src/common/define_enum.h b/src/common/define_enum.h index a9739217476abde6e338cd551031947282ec41f2..68a9b72cec4441dbd5a8933b48e9d2cdca3c38a4 100644 --- a/src/common/define_enum.h +++ b/src/common/define_enum.h @@ -68,7 +68,8 @@ enum OperateID { OP_INIT, OP_GET_ONLY, OP_VOTE_RESET, - OP_WAIT_FOR_ANY + OP_WAIT_FOR_ANY, + OP_PRINT }; enum RetErrCode { diff --git a/src/common/define_plus.h b/src/common/define_plus.h index 8fef88ee3ef330b230358c996210ef4859e8e1cc..c0c0936b961cd8cd3ed9efbd521d165b4de45509 100644 --- a/src/common/define_plus.h +++ b/src/common/define_plus.h @@ -253,6 +253,9 @@ struct HdcSession { bool isSoftReset; // for daemon, Used to record whether a reset command has been received HdcHeartbeat heartbeat; uv_timer_t heartbeatTimer; + bool isRunningOk; + std::string faultInfo; + uint64_t commandCount = 0; HdcSessionStat stat; std::string ToDebugString() @@ -268,6 +271,22 @@ struct HdcSession { return oss.str(); } +#ifdef HDC_HOST + std::string ToDisplayConnectionStr() + { + std::ostringstream oss; + oss << "HdcServer ["; + oss << " sessionId:" << sessionId; + oss << " connectKey:" << Hdc::MaskString(connectKey); + oss << " connType:" << unsigned(connType); + oss << " connect state:" << isRunningOk; + oss << " faultInfo:" << faultInfo; + oss << " commandCount:" << commandCount; + oss << " ]"; + return oss.str(); + } +#endif + HdcSession() : serverOrDaemon(false), handshakeOK(false), isDead(false), voteReset(false), childLoopStatus(&childLoop, "ChildLoop") { @@ -302,6 +321,8 @@ struct HdcSession { #endif verifyType = AuthVerifyType::RSA_3072_SHA512; isSoftReset = false; + isRunningOk = true; + faultInfo = ""; } ~HdcSession() @@ -358,6 +379,30 @@ struct HdcChannel { bool connectLocalDevice = false; bool isStableBuf = false; std::atomic writeFailedTimes; + uint64_t startTime = 0; + uint64_t endTime = 0; + bool isSuccess = false; + std::string faultInfo = ""; + uint16_t commandFlag = 0; + std::string commandParameters = ""; + bool isOnce = false; + +#ifdef HDC_HOST + std::string ToDisplayChannelStr() + { + std::ostringstream oss; + oss << "HdcServerForClient ["; + oss << " channelId:" << channelId; + oss << " connectKey:" << Hdc::MaskString(connectKey); + oss << " command flag:" << commandFlag; + oss << " command parameters:" << commandParameters; + oss << " command result:" << isSuccess; + oss << " command take time:" << (endTime - startTime) << "ms"; + oss << " faultInfo:" << faultInfo; + oss << " ]"; + return oss.str(); + } +#endif }; using HChannel = struct HdcChannel *; diff --git a/src/common/session.cpp b/src/common/session.cpp index f4e6b4b4af8df369643d19f4f28671f846d78060..23c8431fcc4a703630c3f8674e756275666c948d 100755 --- a/src/common/session.cpp +++ b/src/common/session.cpp @@ -512,6 +512,11 @@ HSession HdcSessionBase::MallocSession(bool serverOrDaemon, const ConnType connT return hSession; } +void HdcSessionBase::PrintAllSessionConnection(const uint32_t sessionId) +{ + AdminSession(OP_PRINT, sessionId, nullptr); +} + void HdcSessionBase::FreeSessionByConnectType(HSession hSession) { WRITE_LOG(LOG_INFO, "FreeSessionByConnectType %s", hSession->ToDebugString().c_str()); @@ -578,6 +583,7 @@ void HdcSessionBase::FreeSessionFinally(uv_idle_t *handle) } // Notify Server or Daemon, just UI or display commandline thisClass->NotifyInstanceSessionFree(hSession, true); + thisClass->AdminSession(OP_PRINT, hSession->sessionId, nullptr); // all hsession uv handle has been clear thisClass->AdminSession(OP_REMOVE, hSession->sessionId, nullptr); WRITE_LOG(LOG_INFO, "!!!FreeSessionFinally sessionId:%u finish", hSession->sessionId); @@ -690,6 +696,59 @@ void HdcSessionBase::FreeSession(const uint32_t sessionId) } while (false); } +void HdcSessionBase::PrintSession(const uint32_t sessionId) +{ +#ifdef HDC_HOST + uv_rwlock_rdlock(&lockMapSession); + int count = 0; + for (auto v : mapSession) { + HSession hSession = (HSession)v.second; + auto str = hSession->ToDisplayConnectionStr(); + if (hSession->sessionId == sessionId) { + str = str + " (Current)"; + WRITE_LOG(LOG_INFO, "%s", str.c_str()); + } else { + WRITE_LOG(LOG_DEBUG, "%s", str.c_str()); + } + if (hSession->isRunningOk) { + count++; + } + } + WRITE_LOG(LOG_INFO, "alive session count:%d", count); + uv_rwlock_rdunlock(&lockMapSession); +#endif +} + +HSession HdcSessionBase::VoteReset(const uint32_t sessionId) +{ + HSession hRet = nullptr; + bool needReset; + if (serverOrDaemon) { + uv_rwlock_wrlock(&lockMapSession); + hRet = mapSession[sessionId]; + hRet->voteReset = true; + needReset = true; + for (auto &kv : mapSession) { + if (sessionId == kv.first) { + continue; + } + WRITE_LOG(LOG_DEBUG, "session:%u vote reset, session %u is %s", + sessionId, kv.first, kv.second->voteReset ? "YES" : "NO"); + if (!kv.second->voteReset) { + needReset = false; + } + } + uv_rwlock_wrunlock(&lockMapSession); + } else { + needReset = true; + } + if (needReset) { + WRITE_LOG(LOG_FATAL, "!! session:%u vote reset, passed unanimously !!", sessionId); + abort(); + } + return hRet; +} + HSession HdcSessionBase::AdminSession(const uint8_t op, const uint32_t sessionId, HSession hInput) { HSession hRet = nullptr; @@ -711,6 +770,9 @@ HSession HdcSessionBase::AdminSession(const uint8_t op, const uint32_t sessionId } uv_rwlock_rdunlock(&lockMapSession); break; + case OP_PRINT: + PrintSession(sessionId); + break; case OP_QUERY_REF: uv_rwlock_wrlock(&lockMapSession); if (mapSession.count(sessionId)) { @@ -730,30 +792,7 @@ HSession HdcSessionBase::AdminSession(const uint8_t op, const uint32_t sessionId if (mapSession.count(sessionId) == 0) { break; } - bool needReset; - if (serverOrDaemon) { - uv_rwlock_wrlock(&lockMapSession); - hRet = mapSession[sessionId]; - hRet->voteReset = true; - needReset = true; - for (auto &kv : mapSession) { - if (sessionId == kv.first) { - continue; - } - WRITE_LOG(LOG_DEBUG, "session:%u vote reset, session %u is %s", - sessionId, kv.first, kv.second->voteReset ? "YES" : "NO"); - if (!kv.second->voteReset) { - needReset = false; - } - } - uv_rwlock_wrunlock(&lockMapSession); - } else { - needReset = true; - } - if (needReset) { - WRITE_LOG(LOG_FATAL, "!! session:%u vote reset, passed unanimously !!", sessionId); - abort(); - } + hRet = VoteReset(sessionId); break; default: break; diff --git a/src/common/session.h b/src/common/session.h index 3e0f898a5eb966e8ab03d03f78fd27c69b78a556..aeadbaf96a132f5e5ceb180e7e1c773709a8aee1 100755 --- a/src/common/session.h +++ b/src/common/session.h @@ -96,6 +96,7 @@ public: virtual HSession MallocSession(bool serverOrDaemon, const ConnType connType, void *classModule, uint32_t sessionId = 0); virtual void FreeSession(const uint32_t sessionId); + void PrintAllSessionConnection(const uint32_t sessionId); void WorkerPendding(); int OnRead(HSession hSession, uint8_t *bufPtr, const int bufLen); int Send(const uint32_t sessionId, const uint32_t channelId, const uint16_t commandFlag, const uint8_t *data, @@ -149,6 +150,8 @@ protected: uint32_t dataSize; } __attribute__((packed)); void ClearSessions(); + void PrintSession(const uint32_t sessionId); + HSession VoteReset(const uint32_t sessionId); virtual void JdwpNewFileDescriptor(const uint8_t *buf, const int bytesIO) { } diff --git a/src/common/tcp.cpp b/src/common/tcp.cpp index d6c7ca7fb709d625ac84e6ceabaecbc4bb7598a8..7927f89e60daeac238e5d12e75d896c7ca9928dd 100644 --- a/src/common/tcp.cpp +++ b/src/common/tcp.cpp @@ -79,6 +79,8 @@ void HdcTCPBase::ReadStream(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf while (true) { if (nread == UV_ENOBUFS) { WRITE_LOG(LOG_WARN, "Session IOBuf max, sid:%u", hSession->sessionId); + hSession->isRunningOk = false; + hSession->faultInfo = "io buffer overflow"; break; } else if (nread < 0) { // I originally in the IO main thread, no need to send asynchronous messages, close the socket as soon as @@ -86,11 +88,15 @@ void HdcTCPBase::ReadStream(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf constexpr int bufSize = 1024; char buffer[bufSize] = { 0 }; uv_strerror_r(static_cast(nread), buffer, bufSize); + hSession->isRunningOk = false; + hSession->faultInfo = buffer; WRITE_LOG(LOG_INFO, "HdcTCPBase::ReadStream < 0 %s sid:%u", buffer, hSession->sessionId); break; } if (hSessionBase->FetchIOBuf(hSession, hSession->ioBuf, nread) < 0) { WRITE_LOG(LOG_FATAL, "ReadStream FetchIOBuf error nread:%zd, sid:%u", nread, hSession->sessionId); + hSession->isRunningOk = false; + hSession->faultInfo = "package parse error"; break; } ret = true; diff --git a/src/host/host_tcp.cpp b/src/host/host_tcp.cpp index 2acd13782a2604eb24cfc72956ba8841e87ca5c3..8deb0e32296096bdd94e205f9adbf52539c36ef0 100644 --- a/src/host/host_tcp.cpp +++ b/src/host/host_tcp.cpp @@ -103,6 +103,10 @@ void HdcHostTCP::Connect(uv_connect_t *connection, int status) auto ctrl = ptrConnect->BuildCtrlString(SP_START_SESSION, 0, nullptr, 0); if (status < 0) { WRITE_LOG(LOG_FATAL, "Connect status:%d", status); + hSession->isRunningOk = false; + char buffer[BUF_SIZE_DEFAULT] = { 0 }; + uv_strerror_r(status, buffer, BUF_SIZE_DEFAULT); + hSession->faultInfo += buffer; goto Finish; } if ((hSession->fdChildWorkTCP = Base::DuplicateUvSocket(&hSession->hWorkTCP)) < 0) { @@ -142,6 +146,7 @@ HSession HdcHostTCP::ConnectDaemon(const string &connectKey, bool isCheck) } hSession->isCheck = isCheck; hSession->connectKey = connectKey; + ptrConnect->PrintAllSessionConnection(hSession->sessionId); struct sockaddr_in dest; uv_ip4_addr(ip, port, &dest); uv_connect_t *conn = new(std::nothrow) uv_connect_t(); diff --git a/src/host/host_usb.cpp b/src/host/host_usb.cpp index 8ebe533e0f1be6d8c054ed1b1fa41d3828b168a3..ed7ebd671a30ca7f7b22fced79fa278248367a8e 100644 --- a/src/host/host_usb.cpp +++ b/src/host/host_usb.cpp @@ -176,6 +176,7 @@ bool HdcHostUSB::DetectMyNeed(libusb_device *device, string &sn) return false; } hSession->connectKey = hUSB->serialNumber; + hdcServer->PrintAllSessionConnection(hSession->sessionId); uv_timer_t *waitTimeDoCmd = new(std::nothrow) uv_timer_t; if (waitTimeDoCmd == nullptr) { WRITE_LOG(LOG_FATAL, "DetectMyNeed new waitTimeDoCmd failed"); @@ -594,12 +595,18 @@ int HdcHostUSB::SubmitUsbBio(HSession hSession, bool sendOrRecv, uint8_t *buf, i childRet = libusb_submit_transfer(ep->transfer); hUSB->lockDeviceHandle.unlock(); if (childRet < 0) { + hSession->isRunningOk = false; + hSession->faultInfo += libusb_error_name(ep->transfer->status); + hSession->faultInfo += " "; WRITE_LOG(LOG_FATAL, "SubmitUsbBio libusb_submit_transfer failed, sid:%u ret:%d", hSession->sessionId, childRet); break; } ep->cv.wait(lock, [ep]() { return ep->isComplete; }); if (ep->transfer->status != 0) { + hSession->isRunningOk = false; + hSession->faultInfo += libusb_error_name(ep->transfer->status); + hSession->faultInfo += " "; WRITE_LOG(LOG_FATAL, "SubmitUsbBio transfer failed, sid:%u status:%d", hSession->sessionId, ep->transfer->status); break; diff --git a/src/host/server_for_client.cpp b/src/host/server_for_client.cpp index 99ade4fc145514fcffe87210a50acb108b52f281..5950af12fbe6d395388fe6147beaa40e8569235e 100755 --- a/src/host/server_for_client.cpp +++ b/src/host/server_for_client.cpp @@ -51,6 +51,7 @@ void HdcServerForClient::AcceptClient(uv_stream_t *server, int status) CALLSTAT_GUARD(thisClass->loopMainStatus, server->loop, "HdcServerForClient::AcceptClient"); HChannel hChannel = nullptr; uint32_t uid = thisClass->MallocChannel(&hChannel); + hChannel->startTime = Base::GetRuntimeMSec(); if (!hChannel) { WRITE_LOG(LOG_FATAL, "AcceptClient hChannel is nullptr"); return; @@ -487,28 +488,33 @@ bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandIn switch (formatCommand->cmdFlag) { case CMD_KERNEL_TARGET_DISCOVER: { OrderFindTargets(hChannel); + hChannel->isSuccess = true; ret = false; break; } case CMD_KERNEL_TARGET_LIST: { GetTargetList(hChannel, formatCommandInput); + hChannel->isSuccess = true; ret = false; break; } case CMD_SERVICE_START: { PrintLastError(hChannel); + hChannel->isSuccess = true; ret = false; break; } case CMD_CHECK_SERVER: { WRITE_LOG(LOG_DEBUG, "CMD_CHECK_SERVER command"); ReportServerVersion(hChannel); + hChannel->isSuccess = true; ret = false; break; } case CMD_WAIT_FOR: { WRITE_LOG(LOG_DEBUG, "CMD_WAIT_FOR command"); ret = !WaitForAny(hChannel); + hChannel->isSuccess = ret; break; } case CMD_KERNEL_TARGET_ANY: { @@ -516,6 +522,7 @@ bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandIn WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_ANY %s", __FUNCTION__, formatCommand->parameters.c_str()); #endif ret = GetAnyTarget(hChannel); + hChannel->isSuccess = ret; break; } case CMD_KERNEL_TARGET_CONNECT: { @@ -523,6 +530,7 @@ bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandIn WRITE_LOG(LOG_DEBUG, "%s CMD_KERNEL_TARGET_CONNECT %s", __FUNCTION__, formatCommand->parameters.c_str()); #endif ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str()); + hChannel->isSuccess = ret; break; } case CMD_CHECK_DEVICE: { @@ -530,10 +538,12 @@ bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandIn hChannel->isCheck = true; hChannel->key = formatCommand->parameters.c_str(); ret = NewConnectTry(ptrServer, hChannel, formatCommand->parameters.c_str(), true); + hChannel->isSuccess = ret; break; } case CMD_KERNEL_TARGET_DISCONNECT: { CommandRemoveSession(hChannel, formatCommand->parameters.c_str()); + hChannel->isSuccess = true; break; } // task will be global task,Therefore, it can only be controlled in the global session. @@ -544,20 +554,25 @@ bool HdcServerForClient::DoCommandLocal(HChannel hChannel, void *formatCommandIn echo = EMPTY_ECHO; } EchoClient(hChannel, MSG_OK, const_cast(echo.c_str())); + hChannel->isSuccess = true; break; } case CMD_FORWARD_REMOVE: { RemoveForward(hChannel, formatCommand->parameters.c_str()); + hChannel->isSuccess = true; break; } case CMD_KERNEL_ENABLE_KEEPALIVE: { // just use for 'list targets' now hChannel->keepAlive = true; ret = true; + hChannel->isSuccess = true; break; } default: { EchoClient(hChannel, MSG_FAIL, "ExecuteCommand need connect-key? please confirm a device by help info"); + hChannel->isSuccess = false; + hChannel->faultInfo = "found no devices"; break; } } @@ -696,6 +711,7 @@ bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandI } return ret; } + // Do not specify Target's operations no longer need to put it in the thread. bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput, HDaemonInfo &hdi) { @@ -705,6 +721,8 @@ bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput, formatCommand->cmdFlag == CMD_FORWARD_REMOVE || formatCommand->cmdFlag == CMD_SERVICE_START) { // Main thread command, direct Listen main thread + hChannel->commandFlag = formatCommand->cmdFlag; + hChannel->commandParameters = formatCommand->parameters; ret = DoCommandLocal(hChannel, formatCommandInput); } else { // CONNECT DAEMON's work thread command, non-primary thread if (!CommandMatchDaemonFeature(formatCommand->cmdFlag, hdi)) { @@ -713,6 +731,10 @@ bool HdcServerForClient::DoCommand(HChannel hChannel, void *formatCommandInput, EchoClient(hChannel, MSG_FAIL, "[E002105] Unsupport command"); return false; } + if (formatCommand->cmdFlag != CMD_SHELL_DATA) { + hChannel->commandFlag = formatCommand->cmdFlag; + hChannel->commandParameters = formatCommand->parameters; + } ret = DoCommandRemote(hChannel, formatCommandInput); } return ret; @@ -727,16 +749,22 @@ HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChann ptrServer->AdminDaemonMap(OP_QUERY, hChannel->connectKey, hdi); if (!hdi) { WRITE_LOG(LOG_WARN, "Not match target founded cid:%u", hChannel->channelId); + hChannel->isSuccess = false; + hChannel->faultInfo = "no match targets found"; EchoClient(hChannel, MSG_FAIL, "Not match target founded, check connect-key please"); return nullptr; } if (hdi->connStatus != STATUS_CONNECTED) { WRITE_LOG(LOG_WARN, "Device not found or connected cid:%u", hChannel->channelId); + hChannel->isSuccess = false; + hChannel->faultInfo = "device not found or connected"; EchoClient(hChannel, MSG_FAIL, "[E001005] Device not found or connected"); return nullptr; } if (hdi->hSession == nullptr || hdi->hSession->isDead) { WRITE_LOG(LOG_WARN, "Bind tartget session is null or dead cid:%u", hChannel->channelId); + hChannel->isSuccess = false; + hChannel->faultInfo = "bind tartget session is null or dead"; EchoClient(hChannel, MSG_FAIL, "Bind tartget session is dead"); return nullptr; } @@ -745,6 +773,8 @@ HSession HdcServerForClient::FindAliveSessionFromDaemonMap(const HChannel hChann hdi->hSession->sessionId, hChannel->channelId); const string errMsg = "[E000004]:The communication channel is being established.\r\n"\ "Please wait for several seconds and try again."; + hChannel->isSuccess = false; + hChannel->faultInfo = "handshake is not ready"; EchoClient(hChannel, MSG_FAIL, errMsg.c_str()); return nullptr; }