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 */ 16#include "HdcJdwpSimulator.h" 17using namespace OHOS; 18using namespace OHOS::HiviewDFX; 19static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "JDWP_TEST"}; 20HdcJdwpSimulator::HdcJdwpSimulator(uv_loop_t *loopIn, string pkg) 21{ 22 loop = loopIn; 23 exit = false; 24 pkgName = pkg; 25} 26 27HdcJdwpSimulator::~HdcJdwpSimulator() {} 28 29void HdcJdwpSimulator::FinishWriteCallback(uv_write_t *req, int status) 30{ 31 constexpr int bufSize = 1024; 32 char buf[bufSize] = { 0 }; 33 uv_err_name_r(status, buf, bufSize); 34 HiLog::Info(LABEL, "FinishWriteCallback:%{public}d error:%{public}s", status, buf); 35 delete[](static_cast<uint8_t *>(req->data)); 36 delete req; 37} 38 39RetErrCode HdcJdwpSimulator::SendToStream(uv_stream_t *handleStream, const uint8_t *buf, 40 const int bufLen, const void *finishCallback) 41{ 42 HiLog::Info(LABEL, "HdcJdwpSimulator::SendToStream: %{public}s, %{public}d", buf, bufLen); 43 RetErrCode ret = RetErrCode::ERR_GENERIC; 44 if (bufLen <= 0) { 45 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream wrong bufLen."); 46 return RetErrCode::ERR_GENERIC; 47 } 48 uint8_t *pDynBuf = new uint8_t[bufLen]; 49 if (!pDynBuf) { 50 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream new pDynBuf fail."); 51 return RetErrCode::ERR_GENERIC; 52 } 53 if (memcpy_s(pDynBuf, bufLen, buf, bufLen)) { 54 delete[] pDynBuf; 55 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream memcpy fail."); 56 return RetErrCode::ERR_BUF_ALLOC; 57 } 58 59 uv_write_t *reqWrite = new uv_write_t(); 60 if (!reqWrite) { 61 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream alloc reqWrite fail."); 62 delete[] pDynBuf; 63 return RetErrCode::ERR_GENERIC; 64 } 65 uv_buf_t bfr; 66 while (true) { 67 reqWrite->data = static_cast<void *>(pDynBuf); 68 bfr.base = reinterpret_cast<char *>(pDynBuf); 69 bfr.len = bufLen; 70 if (!uv_is_writable(handleStream)) { 71 HiLog::Info(LABEL, "SendToStream uv_is_unwritable!"); 72 delete[] pDynBuf; 73 delete reqWrite; 74 break; 75 } 76 HiLog::Info(LABEL, "SendToStream buf:%{public}s", pDynBuf); 77 uv_write(reqWrite, handleStream, &bfr, 1, (uv_write_cb)finishCallback); 78 ret = RetErrCode::SUCCESS; 79 break; 80 } 81 return ret; 82} 83 84void HdcJdwpSimulator::alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) 85{ 86 if (suggested_size <= 0) { 87 return; 88 } 89 buf->base = (char *)malloc(suggested_size); 90 buf->len = suggested_size; 91} 92 93#ifndef JS_JDWP_CONNECT 94// Process incoming data. If no data is available, this will block until some 95// arrives. 96void HdcJdwpSimulator::ProcessIncoming(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) 97{ 98 HiLog::Debug(LABEL, "ProcessIncoming :%{public}d", nread); 99 do { 100 if (nread > 0) { 101 std::unique_ptr<char[]> recv = std::make_unique<char[]>(nread + 1); 102 if (memset_s(recv.get(), nread, 0, nread) != EOK) { 103 HiLog::Error(LABEL, "ProcessIncoming memset_s fail."); 104 break; 105 } 106 if (memcpy_s(recv.get(), nread, buf->base, nread) != EOK) { 107 HiLog::Error(LABEL, "ProcessIncoming memcpy_s fail."); 108 break; 109 } 110 for (int i = 0; i < (nread + 1); i++) { 111 HiLog::Info(LABEL, "ProcessIncoming recv2[%{public}d] :%{public}c", i, recv[i]); 112 } 113 114 vector<uint8_t> reply; 115 reply.clear(); 116 reply.insert(reply.end(), HANDSHAKE_MESSAGE.c_str(), 117 HANDSHAKE_MESSAGE.c_str() + HANDSHAKE_MESSAGE.size()); 118 reply.insert(reply.end(), buf->base, buf->base + nread); 119 HiLog::Info(LABEL, "ProcessIncoming--reply server"); 120 uint8_t *buf = reply.data(); 121 122 for (int i = 0; i < (HANDSHAKE_MESSAGE.size() + nread + 1); i++) { 123 HiLog::Info(LABEL, "ProcessIncoming reply%{public}d :%{public}c", i, reply[i]); 124 } 125 SendToStream(client, buf, HANDSHAKE_MESSAGE.size() + nread + 1, 126 (void *)FinishWriteCallback); 127 } else { 128 if (nread != UV_EOF) { 129 constexpr int bufSize = 1024; 130 char buffer[bufSize] = { 0 }; 131 uv_err_name_r(nread, buffer, bufSize); 132 HiLog::Debug(LABEL, "ProcessIncoming error %s\n", buffer); 133 } 134 uv_close((uv_handle_t *)client, NULL); 135 } 136 } while (false); 137 free(buf->base); 138} 139 140// Get new socket fd passed from jdwp control 141void HdcJdwpSimulator::ReceiveNewFd(uv_stream_t *q, ssize_t nread, const uv_buf_t *buf) 142{ 143 HCtxJdwpSimulator ctxJdwp = static_cast<HCtxJdwpSimulator>(q->data); 144 HdcJdwpSimulator *thisClass = static_cast<HdcJdwpSimulator *>(ctxJdwp->thisClass); 145 int pidCurr = static_cast<int>(getpid()); 146 HiLog::Debug(LABEL, "HdcJdwpSimulator::ReceiveNewFd pid: %{public}d, nread: %{public}d\n", 147 pidCurr, nread); 148 if (nread < 0) { 149 if (nread != UV_EOF) { 150 constexpr int bufSize = 1024; 151 char buffer[bufSize] = { 0 }; 152 uv_err_name_r(nread, buffer, bufSize); 153 HiLog::Error(LABEL, "Read error %s\n", buffer); 154 } 155 uv_close((uv_handle_t *)q, NULL); 156 return; 157 } 158 159 uv_pipe_t *pipe = reinterpret_cast<uv_pipe_t *>(q); 160 if (!uv_pipe_pending_count(pipe)) { 161 HiLog::Error(LABEL, "No pending count\n"); 162 return; 163 } 164 uv_handle_type pending = uv_pipe_pending_type(pipe); 165 if (pending != UV_TCP) { 166 HiLog::Debug(LABEL, "None TCP type: %{public}d", pending); 167 } 168 uv_tcp_init(thisClass->loop, &ctxJdwp->newFd); 169 if (uv_accept(q, reinterpret_cast<uv_stream_t *>(&ctxJdwp->newFd)) == 0) { 170 uv_os_fd_t fd; 171 ctxJdwp->hasNewFd = true; 172 uv_fileno(reinterpret_cast<const uv_handle_t *>(&ctxJdwp->newFd), &fd); 173 HiLog::Debug(LABEL, "Jdwp forward pid %{public}d: new fd %{public}d\n", getpid(), fd); 174 uv_read_start(reinterpret_cast<uv_stream_t *>(&ctxJdwp->newFd), alloc_buffer, 175 ProcessIncoming); 176 } else { 177 ctxJdwp->hasNewFd = false; 178 uv_close(reinterpret_cast<uv_handle_t *>(&ctxJdwp->newFd), NULL); 179 } 180} 181#endif // JS_JDWP_CONNECT 182 183void HdcJdwpSimulator::ConnectJdwp(uv_connect_t *connection, int status) 184{ 185 constexpr int bufSize = 1024; 186 char buf[bufSize] = { 0 }; 187 uv_err_name_r(status, buf, bufSize); 188 HiLog::Debug(LABEL, "ConnectJdwp:%{public}d error:%{public}s", status, buf); 189 uint32_t pidCurr = static_cast<uint32_t>(getpid()); 190 HCtxJdwpSimulator ctxJdwp = static_cast<HCtxJdwpSimulator>(connection->data); 191 HdcJdwpSimulator *thisClass = static_cast<HdcJdwpSimulator *>(ctxJdwp->thisClass); 192 delete connection; 193 194#ifdef JS_JDWP_CONNECT 195 string pkgName = thisClass->pkgName; 196 uint32_t pkgSize = pkgName.size() + sizeof(JsMsgHeader); // JsMsgHeader pkgName; 197 uint8_t *info = new uint8_t[pkgSize](); 198 if (!info) { 199 HiLog::Error(LABEL, "ConnectJdwp new info fail."); 200 return; 201 } 202 do { 203 if (memset_s(info, pkgSize, 0, pkgSize) != EOK) { 204 HiLog::Error(LABEL, "ConnectJdwp memset_s fail."); 205 break; 206 } 207 JsMsgHeader *jsMsg = reinterpret_cast<JsMsgHeader *>(info); 208 jsMsg->pid = pidCurr; 209 jsMsg->msgLen = pkgSize; 210 HiLog::Info(LABEL, 211 "ConnectJdwp send pid:%{public}d, pkgName:%{public}s, msgLen:%{public}d,", 212 jsMsg->pid, pkgName.c_str(), jsMsg->msgLen); 213 bool retFail = false; 214 if (memcpy_s(info + sizeof(JsMsgHeader), pkgName.size(), &pkgName[0], pkgName.size()) != 215 EOK) { 216 HiLog::Error(LABEL, "ConnectJdwp memcpy_s fail :%{public}s.", pkgName.c_str()); 217 retFail = true; 218 } 219 if (!retFail) { 220 HiLog::Info(LABEL, "ConnectJdwp send JS msg:%{public}s", info); 221 thisClass->SendToStream(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe), info, pkgSize, 222 (void *)FinishWriteCallback); 223 } 224 } while (false); 225 if (info) { 226 delete[] info; 227 info = nullptr; 228 } 229#else 230 int pidLength = 5; 231 char pid[pidLength] = {0}; 232 if (to_string(pidCurr).length() >= pidLength || sprintf_s(pid, sizeof(pid), "%d", pidCurr) < 0) { 233 HiLog::Info(LABEL, "ConnectJdwp trans pid fail :%{public}d.", pidCurr); 234 return; 235 } 236 HiLog::Info(LABEL, "ConnectJdwp send pid:%{public}s", pid); 237 thisClass->SendToStream(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe), 238 reinterpret_cast<uint8_t *>(pid), sizeof(pidCurr), 239 (void *)FinishWriteCallback); 240 HiLog::Info(LABEL, "ConnectJdwp reading."); 241 uv_read_start(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe), thisClass->alloc_buffer, 242 ReceiveNewFd); 243#endif // JS_JDWP_CONNECT 244} 245 246void *HdcJdwpSimulator::MallocContext() 247{ 248 HCtxJdwpSimulator ctx = nullptr; 249 if ((ctx = new ContextJdwpSimulator()) == nullptr) { 250 return nullptr; 251 } 252 ctx->thisClass = this; 253 ctx->pipe.data = ctx; 254 ctx->hasNewFd = false; 255 return ctx; 256} 257 258void HdcJdwpSimulator::FreeContext() 259{ 260 HiLog::Debug(LABEL, "HdcJdwpSimulator::FreeContext start"); 261 if (!ctxPoint) { 262 return; 263 } 264 if (loop && !uv_is_closing(reinterpret_cast<uv_handle_t *>(&ctxPoint->pipe))) { 265 uv_close(reinterpret_cast<uv_handle_t *>(&ctxPoint->pipe), nullptr); 266 } 267 if (ctxPoint->hasNewFd && loop && 268 !uv_is_closing(reinterpret_cast<uv_handle_t *>(&ctxPoint->newFd))) { 269 uv_close(reinterpret_cast<uv_handle_t *>(&ctxPoint->newFd), nullptr); 270 } 271 delete ctxPoint; 272 ctxPoint = nullptr; 273 HiLog::Debug(LABEL, "HdcJdwpSimulator::FreeContext end"); 274} 275 276bool HdcJdwpSimulator::Connect() 277{ 278 string jdwpCtrlName = "\0ohjpid-control"; 279 uv_connect_t *connect = new uv_connect_t(); 280 ctxPoint = static_cast<HCtxJdwpSimulator>(MallocContext()); 281 if (!ctxPoint) { 282 HiLog::Info(LABEL, "MallocContext failed"); 283 return false; 284 } 285 connect->data = ctxPoint; 286 uv_pipe_init(loop, static_cast<uv_pipe_t *>(&ctxPoint->pipe), 1); 287 HiLog::Info(LABEL, " HdcJdwpSimulator Connect begin"); 288 uv_pipe_connect(connect, &ctxPoint->pipe, jdwpCtrlName.c_str(), ConnectJdwp); 289 return true; 290} 291 292void HdcJdwpSimulator::stop() 293{ 294 HiLog::Debug(LABEL, "HdcJdwpSimulator::stop."); 295 FreeContext(); 296} 297