diff --git a/README_zh.md b/README_zh.md index 97f4b55dab28059c2e6c00d18ee459a5a22c6e71..bbdeb389957f23affc027ab6496ffa3f3a923c00 100644 --- a/README_zh.md +++ b/README_zh.md @@ -1,15 +1,21 @@ -# hdc组件 +# HDC-鸿蒙设备连接器 - [简介](#section662115419449) - [架构](#section15908143623714) - [目录](#section161941989596) + - [下载说明](#section129654513263) + - [1.通过git clone方式下载(建议)](#section161941989591) + - [2.通过网页形式下载](#section161941989592) + - [3.支持环境](#section161941989593) + - [4.BUG上报](#section161941989594) - [使用说明](#section129654513264) - [相关仓](#section1371113476307) +- [FAQ](#section1371113476308) ## 简介 -hdc(Harmony Device Connector) 是OpenHarmony为开发人员提供的用于调试的命令行工具,开发机器上使用设备连接器hdc client/server命令行工具,该工具需支持部署在Windows/Linux/Mac等系统上与鸿蒙设备(或模拟器)进行连接调试通信。PC端hdc工具需要针对以上开发机操作系统平台分别发布相应的版本,设备端hdc daemon需跟随设备镜像发布包括对模拟器进行支持。下文将介绍hdc的常用命令及使用举例。 +HDC(Harmony Device Connector) 是OpenHarmony为开发人员提供的用于调试的命令行工具,开发机器上使用设备连接器hdc client/server命令行工具,该工具需支持部署在Windows/Linux/Mac等系统上与鸿蒙设备(或模拟器)进行连接调试通信。PC端hdc工具需要针对以上开发机操作系统平台分别发布相应的版本,设备端hdc daemon需跟随设备镜像发布包括对模拟器进行支持。下文将介绍hdc的常用命令及使用举例。 ## 架构 @@ -34,11 +40,37 @@ hdc主要有三部分组成: │ └── prebuilt # 预编译目录,存放预编译的二进制文件 ``` +### 下载说明 + + +[1.通过git clone方式下载(建议)](#section161941989591) +``` +外仓命令为: +git clone git@gitee.com:openharmony/developtools_hdc_standard.git +合作仓命令为: +git clone git@gitee.com:OHOS_STD/developtools_hdc_standard.git +``` + +[2.通过网页形式下载](#section161941989592) +通过网页形式下载prebuilt,请使用类似如下URL打开网页: +``` https://gitee.com/openharmony/developtools_hdc_standard/blob/master/prebuilt/windows/hdc-std.exe``` +点击中间下载方式进行下载,windows版本文件大小在**5M左右**,linux版本在**2M左右**,不要使用右击另存为方式进行保存下载,这样下载不对,下载后检查文件大小(**说三遍**)。 + +[3.支持环境](#section161941989593) +支持运行环境 linux版本建议ubuntu20 CentOS8 64位,其他版本相近也应该可以,libc++.so引用错误请使用ldd/readelf等命令检查库引用 windows版本建议windows10 64位,windows8也应该可以,Windows7等EOF版本尚未测试,如果低版本windows winusb库缺失,请使用zadig更新库。 + +[4.BUG上报](#section161941989594) +近期hdc刚开发完成,适配和调整变动较多,如果遇到异常情况,建议按照如下步骤进行排查: +1)首先核对server与daemon版本是否匹配,hdc-std -v, hdcd -v。 +2)更新工程最新的线上代码和预编译文件,是否在后续版本中已解决问题。 +3)规范的和详细的提出issue,我们将尽快跟进。 + + ### 使用说明 -hdc当前支持如下命令: +hdc当前常用命令如下,未尽命令使用hdc -h或者hdc --help查看: -**表 1** hdc命令列表 +**表 1** hdc常用命令列表

Option

@@ -198,4 +230,6 @@ hdc当前支持如下命令: 研发工具链子系统 -**developtools\_hdc\_standard** \ No newline at end of file +**developtools\_hdc\_standard** + +## FAQ \ No newline at end of file diff --git a/prebuilt/linux/hdc_std b/prebuilt/linux/hdc_std index 2c31bd319eeaec08c8cf5aeef63d0c3c8aa95bbf..3f170d86adebd72324b404682ed3dad89b34cea4 100755 Binary files a/prebuilt/linux/hdc_std and b/prebuilt/linux/hdc_std differ diff --git a/prebuilt/windows/hdc_std.exe b/prebuilt/windows/hdc_std.exe index 18f49eba614fe6613d39526d5033f59c11cae992..4174db891ebcf5cb7f805be1a945631b18caecd6 100644 --- a/prebuilt/windows/hdc_std.exe +++ b/prebuilt/windows/hdc_std.exe @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f969acb481533102a41fc2262a18d99d2cd9f58bb7d7860519f44b225cf7918 -size 3301376 +oid sha256:7d95e291cc173be53b2542f593f65cbeb726c8d6d6f5bf2edc5cfdfc2c4db607 +size 3301888 diff --git a/src/common/define.h b/src/common/define.h index ee2f6ad44d75c45e29d54dc539a158087b707cfe..c41a651d7e051a7ed0350185734de3be41d62cda 100644 --- a/src/common/define.h +++ b/src/common/define.h @@ -48,14 +48,16 @@ constexpr uint16_t MAX_IP_PORT = 65535; constexpr uint8_t STREAM_MAIN = 0; // work at main thread constexpr uint8_t STREAM_WORK = 1; // work at work thread constexpr uint16_t MAX_CONNECTKEY_SIZE = 32; // usb sn/tcp ipport -constexpr uint8_t MAX_IO_OVERLAP = 255; // +constexpr uint8_t MAX_IO_OVERLAP = 32; // test on windows 32 is OK constexpr auto TIME_BASE = 1000; // time unit conversion base value constexpr uint16_t AID_SHELL = 2000; +// double-word(hex)=[0]major[1][2]monor[3][4]version[5]fix(a-p)[6][7]reserve +constexpr uint32_t HDC_VERSION_NUMBER = 0x10100f00; // general one argument command argc constexpr int CMD_ARG1_COUNT = 2; // The first child versions must match, otherwise server and daemon must be upgraded -const string VERSION_NUMBER = "1.1.0p"; // same with openssl version, 1.1.2==VERNUMBER 0x10102000 +const string VERSION_NUMBER = "1.1.0q"; // same with openssl version, 1.1.2==VERNUMBER 0x10102000 const string HANDSHAKE_MESSAGE = "OHOS HDC"; // sep not char '-', not more than 11 bytes const string PACKET_FLAG = "HW"; // must 2bytes const string EMPTY_ECHO = "[Empty]"; @@ -90,6 +92,6 @@ const string CMDSTR_FORWARD_RPORT = "rport"; const string CMDSTR_APP_INSTALL = "install"; const string CMDSTR_APP_UNINSTALL = "uninstall"; const string CMDSTR_APP_SIDELOAD = "sideload"; -const string CMDSTR_LIST_JDWP = "list jpid"; +const string CMDSTR_LIST_JDWP = "jpid"; } // namespace Hdc #endif // HDC_DEFINE_H diff --git a/src/common/define_plus.h b/src/common/define_plus.h index c3de4a5b10044a4c675c1cc2738dd968776831eb..ba34687dfd1ab8d4cffc97e8f397eb5113d396e0 100644 --- a/src/common/define_plus.h +++ b/src/common/define_plus.h @@ -122,6 +122,7 @@ enum HdcCommand { CMD_UNITY_JPID, // Shell commands types CMD_SHELL_INIT = 2000, + CMD_SHELL_DATA, // Forward commands types CMD_FORWARD_INIT = 2500, CMD_FORWARD_CHECK, diff --git a/src/common/file.cpp b/src/common/file.cpp index 834024b46031b541cc8f711b91e2c1995b579528..ab105434a4302832d91314773b9dc2a5002aaf71 100644 --- a/src/common/file.cpp +++ b/src/common/file.cpp @@ -37,57 +37,65 @@ void HdcFile::StopTask() // Send supported below styles // send|recv path/filename path/filename // send|recv filename path -bool HdcFile::BeginTransfer(CtxFile *context, const char *command) +bool HdcFile::BeginTransfer(CtxFile *context, const string &command) { int argc = 0; - int srcOffset = 0; bool ret = false; + char **argv = Base::SplitCommandToArgs(command.c_str(), &argc); + if (argc < CMD_ARG1_COUNT || argv == nullptr) { + LogMsg(MSG_FAIL, "Transfer path split failed"); + if (argv) { + delete[]((char *)argv); + } + return false; + } + if (!GetLocalRemotePath(context, command.c_str(), argc, argv)) { + delete[]((char *)argv); + return false; + } + do { + ++refCount; + uv_fs_open(loopTask, &context->fsOpenReq, context->localPath.c_str(), O_RDONLY, S_IWUSR | S_IRUSR, OnFileOpen); + context->master = true; + ret = true; + } while (false); + if (!ret) { + LogMsg(MSG_FAIL, "Transfer path failed, Master:%s Slave:%s", context->localPath.c_str(), + context->remotePath.c_str()); + } + delete[]((char *)argv); + return ret; +} + +bool HdcFile::GetLocalRemotePath(CtxFile *context, const char *command, int argc, char **argv) +{ + int srcArgvIndex = 0; const string CMD_OPTION_TSTMP = "-a"; const string CMD_OPTION_SYNC = "-sync"; const string CMD_OPTION_ZIP = "-z"; - - char **argv = Base::SplitCommandToArgs(command, &argc); - if (argc < CMD_ARG1_COUNT) { - goto Finish; - } - context->localPath = argv[argc - 2]; for (int i = 0; i < argc - CMD_ARG1_COUNT; i++) { if (argv[i] == CMD_OPTION_ZIP) { context->transferConfig.compressType = COMPRESS_LZ4; - srcOffset += strlen(argv[i]) + 1; + ++srcArgvIndex; } else if (argv[i] == CMD_OPTION_SYNC) { context->transferConfig.updateIfNew = true; - srcOffset += strlen(argv[i]) + 1; + ++srcArgvIndex; } else if (argv[i] == CMD_OPTION_TSTMP) { context->transferConfig.holdTimestamp = true; - srcOffset += strlen(argv[i]) + 1; + ++srcArgvIndex; + } else if (argv[i][0] == '-') { + LogMsg(MSG_FAIL, "Unknow file option: %s", argv[i]); + return false; } } context->remotePath = argv[argc - 1]; - if (argc > CMD_ARG1_COUNT) { - context->localPath - = std::string(command + srcOffset, strlen(command) - srcOffset - context->remotePath.size() - 1); - } else { - context->localPath = argv[0]; - } - + context->localPath = argv[argc - 2]; if (!Base::CheckDirectoryOrPath(context->localPath.c_str(), true, true)) { - goto Finish; + LogMsg(MSG_FAIL, "Src not exist, path: %s", context->localPath.c_str()); + return false; } context->localName = Base::GetFullFilePath(context->localPath); - ++refCount; - uv_fs_open(loopTask, &context->fsOpenReq, context->localPath.c_str(), O_RDONLY, S_IWUSR | S_IRUSR, OnFileOpen); - context->master = true; - ret = true; - -Finish: - if (!ret) { - LogMsg(MSG_FAIL, "Transfer master path failed"); - } - if (argv) { - delete[]((char *)argv); - } - return ret; + return true; } void HdcFile::CheckMaster(CtxFile *context) @@ -107,7 +115,7 @@ void HdcFile::TransferSummary(CtxFile *context) { uint64_t nMSec = Base::GetRuntimeMSec() - context->transferBegin; double fRate = static_cast(context->indexIO) / nMSec; // / /1000 * 1000 = 0 - LogMsg(MSG_OK, "FileTransfer finish, Size:%lld time:%lldms rate:%lfkB/s", context->indexIO, nMSec, fRate); + LogMsg(MSG_OK, "FileTransfer finish, Size:%lld time:%lldms rate:%.2lfkB/s", context->indexIO, nMSec, fRate); } bool HdcFile::SlaveCheck(uint8_t *payload, const int payloadSize) @@ -149,7 +157,8 @@ bool HdcFile::CommandDispatch(const uint16_t command, uint8_t *payload, const in bool ret = true; switch (command) { case CMD_FILE_INIT: { // initial - ret = BeginTransfer(&ctxNow, (char *)payload); + string s = string((char *)payload, payloadSize); + ret = BeginTransfer(&ctxNow, s); ctxNow.transferBegin = Base::GetRuntimeMSec(); break; } diff --git a/src/common/file.h b/src/common/file.h index 854336f3ce6dc86faba968dce00d1b77be2eab59..a36e4239471f571d9c0b301e8e334e85f092635d 100644 --- a/src/common/file.h +++ b/src/common/file.h @@ -30,9 +30,10 @@ private: bool SlaveCheck(uint8_t *payload, const int payloadSize); void CheckMaster(CtxFile *context); void WhenTransferFinish(CtxFile *context); - bool BeginTransfer(CtxFile *context, const char *command); + bool BeginTransfer(CtxFile *context, const string &command); void TransferSummary(CtxFile *context); + bool GetLocalRemotePath(CtxFile *context, const char *command, int argc, char **argv); }; -} // namespace Hdc +} // namespace Hdc #endif \ No newline at end of file diff --git a/src/common/transfer.cpp b/src/common/transfer.cpp index 9bb86d7637f079b178a9378b0b1107dacea65244..b1d1d96d4faf738fa731c99e5df6f33c43a5906b 100644 --- a/src/common/transfer.cpp +++ b/src/common/transfer.cpp @@ -60,7 +60,7 @@ int HdcTransferBase::SimpleFileIO(CtxFile *context, uint64_t index, uint8_t *sen CtxFileIO *ioContext = new CtxFileIO(); bool ret = false; while (true) { - if (!buf || !ioContext || !bytes) { + if (!buf || !ioContext || bytes < 0) { break; } uv_fs_t *req = &ioContext->fs; @@ -74,10 +74,7 @@ int HdcTransferBase::SimpleFileIO(CtxFile *context, uint64_t index, uint8_t *sen } else { // The US_FS_WRITE here must be brought into the actual file offset, which cannot be incorporated with local // accumulated index because UV_FS_WRITE will be executed multiple times and then trigger a callback. - if (!sendBuf || !bytes) { - break; - } - if (memcpy_s(ioContext->bufIO, bytes, sendBuf, bytes) != EOK) { + if (bytes > 0 && memcpy_s(ioContext->bufIO, bytes, sendBuf, bytes) != EOK) { break; } uv_buf_t iov = uv_buf_init(reinterpret_cast(ioContext->bufIO), bytes); @@ -143,23 +140,24 @@ bool HdcTransferBase::SendIOPayload(CtxFile *context, int index, uint8_t *data, payloadHead.compressType = context->transferConfig.compressType; payloadHead.uncompressSize = dataSize; payloadHead.index = index; - switch (payloadHead.compressType) { + if (dataSize > 0) { + switch (payloadHead.compressType) { #ifdef HARMONY_PROJECT - case COMPRESS_LZ4: { - // clang-format off - compressSize = LZ4_compress_default((const char *)data, (char *)sendBuf + payloadPrefixReserve, - dataSize, dataSize); - // clang-format on - break; - } + case COMPRESS_LZ4: { + compressSize = LZ4_compress_default((const char *)data, (char *)sendBuf + payloadPrefixReserve, + dataSize, dataSize); + break; + } #endif - default: { // COMPRESS_NONE - if (memcpy_s(sendBuf + payloadPrefixReserve, sendBufSize - payloadPrefixReserve, data, dataSize) != EOK) { - delete[] sendBuf; - return false; + default: { // COMPRESS_NONE + if (memcpy_s(sendBuf + payloadPrefixReserve, sendBufSize - payloadPrefixReserve, data, dataSize) + != EOK) { + delete[] sendBuf; + return false; + } + compressSize = dataSize; + break; } - compressSize = dataSize; - break; } } payloadHead.compressSize = compressSize; @@ -188,12 +186,10 @@ void HdcTransferBase::OnFileIO(uv_fs_t *req) uv_fs_req_cleanup(req); --thisClass->refCount; while (true) { - if (req->result <= 0) { // Read error or master read completion + if (req->result < 0) { + WRITE_LOG(LOG_DEBUG, "OnFileIO error: %s", uv_strerror((int)req->result)); + context->closeNotify = true; tryFinishIO = true; - if (req->result < 0) { - WRITE_LOG(LOG_DEBUG, "OnFileIO error: %s", uv_strerror((int)req->result)); - context->closeNotify = true; - } break; } context->indexIO += req->result; @@ -202,9 +198,11 @@ void HdcTransferBase::OnFileIO(uv_fs_t *req) tryFinishIO = true; break; } - // read continue until result >0, let single file packet +packet header less than GetMaxBufSize() - constexpr auto maxBufFactor = 0.8; - thisClass->SimpleFileIO(context, context->indexIO, nullptr, Base::GetMaxBufSize() * maxBufFactor); + if (context->indexIO < context->fileSize) { + // read continue until result >0, let single file packet +packet header less than GetMaxBufSize() + constexpr auto maxBufFactor = 0.8; + thisClass->SimpleFileIO(context, context->indexIO, nullptr, Base::GetMaxBufSize() * maxBufFactor); + } } else if (req->fs_type == UV_FS_WRITE) { // write if (context->indexIO >= context->fileSize) { // The active end must first read it first, but you can't make Finish first, because Slave may not @@ -246,15 +244,16 @@ void HdcTransferBase::OnFileOpen(uv_fs_t *req) uv_fs_t fs; Base::ZeroStruct(fs.statbuf); uv_fs_fstat(nullptr, &fs, context->fsOpenReq.result, nullptr); - uv_fs_req_cleanup(&fs); - TransferConfig &st = context->transferConfig; st.fileSize = fs.statbuf.st_size; st.optionalName = context->localName; st.atime = fs.statbuf.st_atim.tv_sec; st.mtime = fs.statbuf.st_mtim.tv_sec; st.path = context->remotePath; + // update ctxNow=context child value + context->fileSize = st.fileSize; + uv_fs_req_cleanup(&fs); thisClass->CheckMaster(context); } else { // write thisClass->SendToAnother(thisClass->commandBegin, nullptr, 0); @@ -340,21 +339,23 @@ bool HdcTransferBase::RecvIOPayload(CtxFile *context, uint8_t *data, int dataSiz return false; } int clearSize = 0; - switch (pld.compressType) { + if (pld.compressSize > 0) { + switch (pld.compressType) { #ifdef HARMONY_PROJECT - case COMPRESS_LZ4: { - clearSize = LZ4_decompress_safe((const char *)data + payloadPrefixReserve, (char *)clearBuf, - pld.compressSize, pld.uncompressSize); - break; - } + case COMPRESS_LZ4: { + clearSize = LZ4_decompress_safe((const char *)data + payloadPrefixReserve, (char *)clearBuf, + pld.compressSize, pld.uncompressSize); + break; + } #endif - default: { // COMPRESS_NONE - if (memcpy_s(clearBuf, pld.uncompressSize, data + payloadPrefixReserve, pld.compressSize) != EOK) { - delete[] clearBuf; - return false; + default: { // COMPRESS_NONE + if (memcpy_s(clearBuf, pld.uncompressSize, data + payloadPrefixReserve, pld.compressSize) != EOK) { + delete[] clearBuf; + return false; + } + clearSize = pld.compressSize; + break; } - clearSize = pld.compressSize; - break; } } while (true) { diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index cba5cb7676325febadcd572ec45a0e9bbf5f8529..c96e738709e12e679479f6e013beb5bfdf678fa9 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -111,7 +111,7 @@ bool HdcDaemon::RedirectToTask(HTaskInfo hTaskInfo, HSession hSession, const uin ret = TaskCommandDispatch(hTaskInfo, TYPE_UNITY, command, payload, payloadSize); break; case CMD_SHELL_INIT: - case CMD_KERNEL_ECHO_RAW: + case CMD_SHELL_DATA: ret = TaskCommandDispatch(hTaskInfo, TYPE_SHELL, command, payload, payloadSize); break; case CMD_FILE_CHECK: diff --git a/src/daemon/daemon_unity.cpp b/src/daemon/daemon_unity.cpp index 34b578d1d281abd3afe0a8f29f8d40c73535abe6..9b4ba1e7f228b1f781e2060153dd2a19fd455643 100644 --- a/src/daemon/daemon_unity.cpp +++ b/src/daemon/daemon_unity.cpp @@ -166,14 +166,14 @@ bool HdcDaemonUnity::RemountDevice() return true; } -bool HdcDaemonUnity::RebootDevice(const uint8_t *cmd, const int cmdSize) +bool HdcDaemonUnity::RebootDevice(const string &cmd) { sync(); string propertyVal; - if (!cmdSize) { + if (!cmd.size()) { propertyVal = "reboot"; } else { - propertyVal = Base::StringFormat("reboot,%s", cmd); + propertyVal = Base::StringFormat("reboot,%s", cmd.c_str()); } return Base::SetHdcProperty(rebootProperty.c_str(), propertyVal.c_str()); } @@ -228,9 +228,10 @@ bool HdcDaemonUnity::CommandDispatch(const uint16_t command, uint8_t *payload, c bool ret = true; HdcDaemon *daemon = (HdcDaemon *)taskInfo->ownerSessionClass; // Both are not executed, do not need to be detected 'childReady' + string strPayload = string((char *)payload, payloadSize); switch (command) { case CMD_UNITY_EXECUTE: { - ExecuteShell((char *)payload); + ExecuteShell((char *)strPayload.c_str()); break; } case CMD_UNITY_REMOUNT: { @@ -240,21 +241,21 @@ bool HdcDaemonUnity::CommandDispatch(const uint16_t command, uint8_t *payload, c } case CMD_UNITY_REBOOT: { ret = false; - RebootDevice(payload, payloadSize); + RebootDevice(strPayload); break; } case CMD_UNITY_RUNMODE: { ret = false; - SetDeviceRunMode(daemon, (const char *)payload); + SetDeviceRunMode(daemon, strPayload.c_str()); break; } case CMD_UNITY_HILOG: { - GetHiLog((const char *)payload); + GetHiLog(strPayload.c_str()); break; } case CMD_UNITY_ROOTRUN: { ret = false; - if (payloadSize != 0 && !strcmp((char *)payload, "r")) { + if (payloadSize != 0 && !strcmp((char *)strPayload.c_str(), "r")) { Base::SetHdcProperty("persist.hdc.root", "0"); } else { Base::SetHdcProperty("persist.hdc.root", "1"); @@ -263,7 +264,7 @@ bool HdcDaemonUnity::CommandDispatch(const uint16_t command, uint8_t *payload, c break; } case CMD_UNITY_TERMINATE: { - daemon->PostStopInstanceMessage(!strcmp((char *)payload, "1")); + daemon->PostStopInstanceMessage(!strcmp((char *)strPayload.c_str(), "1")); break; } case CMD_UNITY_BUGREPORT_INIT: { diff --git a/src/daemon/daemon_unity.h b/src/daemon/daemon_unity.h index d95ed18313ea21920b8beea55a7c85fca8be203e..6b82378118ac6032a497be2401b18242edc18bc0 100644 --- a/src/daemon/daemon_unity.h +++ b/src/daemon/daemon_unity.h @@ -31,7 +31,7 @@ private: bool FindMountDeviceByPath(const char *toQuery, char *dev); bool RemountPartition(const char *dir); bool RemountDevice(); - bool RebootDevice(const uint8_t *cmd, const int cmdSize); + bool RebootDevice(const string &cmd); bool SetDeviceRunMode(void *daemonIn, const char *cmd); bool GetHiLog(const char *cmd); bool ListJdwpProcess(void *daemonIn); diff --git a/src/daemon/shell.cpp b/src/daemon/shell.cpp index f19aa480410fc624f24ed87271dafc719a20f542..5e77e6f404118097fe0b00b29e476a065c160670 100644 --- a/src/daemon/shell.cpp +++ b/src/daemon/shell.cpp @@ -57,6 +57,23 @@ void HdcShell::StopTask() runningProtect = false; }; +bool HdcShell::SpecialSignal(uint8_t ch) +{ + const uint8_t TXT_SIGNAL_ETX = 0x3; + bool ret = true; + switch (ch) { + case TXT_SIGNAL_ETX: { // Ctrl+C + pid_t tpgid = tcgetpgrp(fdPTY); + kill(tpgid, SIGINT); + break; + } + default: + ret = false; + break; + } + return ret; +} + bool HdcShell::CommandDispatch(const uint16_t command, uint8_t *payload, const int payloadSize) { switch (command) { @@ -67,13 +84,15 @@ bool HdcShell::CommandDispatch(const uint16_t command, uint8_t *payload, const i } break; } - case CMD_KERNEL_ECHO_RAW: + case CMD_SHELL_DATA: if (!childReady) { WRITE_LOG(LOG_DEBUG, "Shell not running"); return false; } - // payloadSize tail with \0 - childShell->Write(payload, payloadSize - 1); + if (payloadSize == 1 && SpecialSignal(payload[0])) { + } else { + childShell->Write(payload, payloadSize); + } break; default: break; @@ -120,7 +139,7 @@ int HdcShell::CreateSubProcessPTY(const char *cmd, const char *arg0, const char close(ptm); return -2; } - + fcntl(ptm, F_SETFD, FD_CLOEXEC); if (ptsname_r(ptm, devname, sizeof(devname)) != 0) { WRITE_LOG(LOG_DEBUG, "Trouble with ptmx, error:%s", strerror(errno)); close(ptm); @@ -151,10 +170,6 @@ bool HdcShell::FinishShellProc(const void *context, const bool result, const str bool HdcShell::ChildReadCallback(const void *context, uint8_t *buf, const int size) { HdcShell *thisClass = (HdcShell *)context; - if (size == CMD_ARG1_COUNT && *buf == 0x5e && *(buf + 1) == 0x43) { - WRITE_LOG(LOG_WARN, "sh.ChildReadCallback fstop"); - thisClass->TaskFinish(); - } if (!thisClass->SendToAnother(CMD_KERNEL_ECHO_RAW, (uint8_t *)buf, size)) { thisClass->TaskFinish(); } diff --git a/src/daemon/shell.h b/src/daemon/shell.h index 0f25378cf8570719e7106a31f19390af1790dd98..51a80379a9b96fd37177f1d770f2dd5c9b5ef8e5 100644 --- a/src/daemon/shell.h +++ b/src/daemon/shell.h @@ -32,6 +32,7 @@ private: static bool FinishShellProc(const void *context, const bool result, const string exitMsg); static bool ChildReadCallback(const void *context, uint8_t *buf, const int size); int ChildForkDo(const char *devname, int ptm, const char *cmd, const char *arg0, const char *arg1); + bool SpecialSignal(uint8_t ch); pid_t pidShell = 0; int fdPTY; diff --git a/src/host/client.cpp b/src/host/client.cpp index 5648286f0642de414d565188e13c67b15bd06f52..80327634f0246ffc99ff1dd7762c6a1bf4d9367a 100644 --- a/src/host/client.cpp +++ b/src/host/client.cpp @@ -220,12 +220,11 @@ void HdcClient::ReadStd(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { HChannel hChannel = (HChannel)stream->data; HdcClient *thisClass = (HdcClient *)hChannel->clsChannel; - char *pCmd = hChannel->bufStd; + char *command = hChannel->bufStd; if (nread <= 0) { return; // error } - thisClass->Send(hChannel->channelId, (uint8_t *)pCmd, strlen(pCmd) + 1); - WRITE_LOG(LOG_DEBUG, "send:%s", pCmd); + thisClass->Send(hChannel->channelId, (uint8_t *)command, strlen(command)); Base::ZeroArray(hChannel->bufStd); } diff --git a/src/host/client.h b/src/host/client.h index ea112ba8f7d8e83a721137f4183ad3828a2c4909..6d315d549b4d9582e57f4bce39f9100ed56157d6 100644 --- a/src/host/client.h +++ b/src/host/client.h @@ -29,31 +29,30 @@ protected: private: static void DoCtrlServiceWork(uv_check_t *handle); static void Connect(uv_connect_t *connection, int status); - int ConnectServerForClient(const char *stringIP, uint16_t port); - void BindLocalStd(); - int ReadChannel(HChannel hChannel, uint8_t *buf, const int bytesIO); - void BindLocalStd(HChannel hChannel); static void AllocStdbuf(uv_handle_t *handle, size_t sizeWanted, uv_buf_t *buf); static void ReadStd(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); static void CommandWorker(uv_timer_t *handle); + int ConnectServerForClient(const char *stringIP, uint16_t port); + int ReadChannel(HChannel hChannel, uint8_t *buf, const int bytesIO); + int PreHandshake(HChannel hChannel, const uint8_t *buf); string AutoConnectKey(string &doCommand, const string &preConnectKey) const; uint32_t GetLastPID(); bool StartKillServer(const char *cmd, bool startOrKill); + void BindLocalStd(); + void BindLocalStd(HChannel hChannel); void ModifyTty(bool setOrRestore, uv_tty_t *tty); - int PreHandshake(HChannel hChannel, const uint8_t *buf); void NotifyInstanceChannelFree(HChannel hChannel); #ifndef _WIN32 termios terminalState; #endif - - HChannel channel; string connectKey; + string command; uint16_t debugRetryCount; + bool bShellInteractive = false; uv_timer_t waitTimeDoCmd; uv_check_t ctrlServerWork; - string command; - bool bShellInteractive = false; + HChannel channel; }; } // namespace Hdc #endif \ No newline at end of file diff --git a/src/host/main.cpp b/src/host/main.cpp index 3720718120df8337d88dfa54d6bf3d2f54c03e36..729ad3814916ba90e9d1a4492df54d8cd2eb9573 100644 --- a/src/host/main.cpp +++ b/src/host/main.cpp @@ -83,6 +83,7 @@ int SplitOptionAndCommand(int argc, const char **argv, string &outOption, string { bool foundCommand = false; int resultChild = 0; + // we want to start from 1, ignore argv[0], but it has issue for (int i = 0; i < argc; ++i) { if (!foundCommand) { resultChild = IsRegisterCommand(outCommand, argv[i], (i == argc - 1) ? nullptr : argv[i + 1]); @@ -96,7 +97,9 @@ int SplitOptionAndCommand(int argc, const char **argv, string &outOption, string } if (foundCommand) { outCommand += outCommand.size() ? " " : ""; - outCommand += argv[i]; + string rawCmd = argv[i]; + string packageCmd = Base::StringFormat("\"%s\"", argv[i]); + outCommand += rawCmd.find(" ") == string::npos ? rawCmd : packageCmd; } else { outOption += outOption.size() ? " " : ""; outOption += argv[i]; @@ -141,7 +144,7 @@ int RunClientMode(string &commands, string &serverListenString, string &connectK uv_loop_init(&loopMain); HdcClient client(false, DEFAULT_SERVER_ADDR, &loopMain); if (!commands.size()) { - Base::PrintMessage("Nothing to do..."); + Base::PrintMessage("Unknow operation command..."); TranslateCommand::Usage(); return 0; } diff --git a/src/host/server_for_client.cpp b/src/host/server_for_client.cpp index a5185af29e63f6ac2f0eef5ffd3791dabde28b71..cee7dd3f784e23a1eff53a404fc1b527a02b49be 100644 --- a/src/host/server_for_client.cpp +++ b/src/host/server_for_client.cpp @@ -398,7 +398,7 @@ bool HdcServerForClient::TaskCommand(HChannel hChannel, void *formatCommandInput { TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; HdcServer *ptrServer = (HdcServer *)clsServer; - int sizeSend = formatCommand->paraments.size() == 0 ? 0 : (formatCommand->paraments.size() + 1); + int sizeSend = formatCommand->paraments.size(); string cmdFlag; uint8_t sizeCmdFlag = 0; if (CMD_FILE_INIT == formatCommand->cmdFlag) { @@ -438,12 +438,12 @@ bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandI { TranslateCommand::FormatCommand *formatCommand = (TranslateCommand::FormatCommand *)formatCommandInput; bool ret = false; - int sizeSend = formatCommand->paraments.size() == 0 ? 0 : (formatCommand->paraments.size() + 1); + int sizeSend = formatCommand->paraments.size(); string cmdFlag; switch (formatCommand->cmdFlag) { // Some simple commands only need to forward the instruction, no need to start Task case CMD_SHELL_INIT: - case CMD_KERNEL_ECHO_RAW: + case CMD_SHELL_DATA: case CMD_UNITY_EXECUTE: case CMD_UNITY_TERMINATE: case CMD_UNITY_REMOUNT: @@ -452,7 +452,6 @@ bool HdcServerForClient::DoCommandRemote(HChannel hChannel, void *formatCommandI case CMD_UNITY_HILOG: case CMD_UNITY_ROOTRUN: case CMD_UNITY_JPID: { - // strlen+1 Prevent DAEMON memory sticks from causing Strlen errors if (!SendToDaemon(hChannel, formatCommand->cmdFlag, (uint8_t *)formatCommand->paraments.c_str(), sizeSend)) { break; @@ -604,8 +603,7 @@ int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const in if (!hChannel->handshakeOK) { return ChannelHandShake(hChannel, bufPtr, bytesIO); } - TranslateCommand::FormatCommand formatCommand; - Base::ZeroStruct(formatCommand); + struct TranslateCommand::FormatCommand formatCommand = { 0 }; if (!hChannel->interactiveShellMode) { string retEcho = String2FormatCommand((char *)bufPtr, bytesIO, &formatCommand); if (retEcho.length()) { @@ -621,8 +619,8 @@ int HdcServerForClient::ReadChannel(HChannel hChannel, uint8_t *bufPtr, const in return ret; } } else { - formatCommand.paraments = (char *)bufPtr; - formatCommand.cmdFlag = CMD_KERNEL_ECHO_RAW; + formatCommand.paraments = string((char *)bufPtr, bytesIO); + formatCommand.cmdFlag = CMD_SHELL_DATA; } if (!DoCommand(hChannel, &formatCommand)) { return -3; // error or want close diff --git a/src/host/translate.cpp b/src/host/translate.cpp index 195cafc7ed67089abab5a9ad42fba3431fd8e529..c6126719a7f03c6630abf7943843273d532f644b 100644 --- a/src/host/translate.cpp +++ b/src/host/translate.cpp @@ -40,7 +40,7 @@ namespace TranslateCommand { "\n" "service commands(on daemon):\n" " target mount - Set /system /vendor partition read-write\n" - " target boot [bootloader|recovery] - Reboot the device or boot into bootloader\\recovery.\n" + " target boot [-bootloader|-recovery] - Reboot the device or boot into bootloader\\recovery.\n" " smode [-r] - Restart daemon with root permissions, '-r' to cancel root\n" " permissions\n" " tmode usb - Reboot the device, listening on USB\n" diff --git a/src/test/ut_command.cpp b/src/test/ut_command.cpp index 24b6b0ed5ba816b7459c81fc2e2bb21dad30858d..95b4c0bd83639db8b13f3f95022d27c5eb732478 100644 --- a/src/test/ut_command.cpp +++ b/src/test/ut_command.cpp @@ -106,7 +106,7 @@ int TestTaskCommand(int method, const string &debugServerPort, const string &deb TestRunClient(debugServerPort, debugConnectKey, bufString); break; case UT_TEST_TMP: - TestRunClient(debugServerPort, debugConnectKey, "shell pwd"); + TestRunClient(debugServerPort, debugConnectKey, "shell"); #ifdef DEF_NULL while (true) { uv_sleep(50); @@ -126,6 +126,8 @@ int TestTaskCommand(int method, const string &debugServerPort, const string &deb TestRunClient(debugServerPort, debugConnectKey, "file send /mnt/hgfs/vtmp/f.txt /tmp/f2.txt"); TestRunClient(debugServerPort, debugConnectKey, "file recv /tmp/f2.txt /mnt/hgfs/vtmp/f2.txt"); TestRunClient(debugServerPort, debugConnectKey, "shell find /proc"); + TestRunClient(debugServerPort, debugConnectKey, "file send \"/d/a b/1.txt\" \"/d/a b/2.txt\""); + TestRunClient(debugServerPort, debugConnectKey, "file recv \"/d/a b/1.txt\" \"/d/a b/2.txt\""); #endif break; default: