diff options
| -rw-r--r-- | adbconnection/adbconnection.cc | 302 | ||||
| -rw-r--r-- | adbconnection/adbconnection.h | 22 | ||||
| -rw-r--r-- | dt_fd_forward/dt_fd_forward.cc | 69 | ||||
| -rw-r--r-- | dt_fd_forward/dt_fd_forward.h | 4 | ||||
| -rw-r--r-- | dt_fd_forward/export/fd_transport.h | 6 | ||||
| -rwxr-xr-x | tools/dt_fds_forward.py | 11 |
6 files changed, 341 insertions, 73 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc index 80cfc83d3c..56677c9be6 100644 --- a/adbconnection/adbconnection.cc +++ b/adbconnection/adbconnection.cc @@ -42,6 +42,7 @@ #include "cutils/sockets.h" #endif +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/eventfd.h> @@ -49,17 +50,35 @@ namespace adbconnection { +// Messages sent from the transport using dt_fd_forward::kListenStartMessage; using dt_fd_forward::kListenEndMessage; using dt_fd_forward::kAcceptMessage; using dt_fd_forward::kCloseMessage; +// Messages sent to the transport +using dt_fd_forward::kPerformHandshakeMessage; +using dt_fd_forward::kSkipHandshakeMessage; + using android::base::StringPrintf; +static constexpr const char kJdwpHandshake[14] = { + 'J', 'D', 'W', 'P', '-', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e' +}; + static constexpr int kEventfdLocked = 0; static constexpr int kEventfdUnlocked = 1; static constexpr int kControlSockSendTimeout = 10; +static constexpr size_t kPacketHeaderLen = 11; +static constexpr off_t kPacketSizeOff = 0; +static constexpr off_t kPacketIdOff = 4; +static constexpr off_t kPacketCommandSetOff = 9; +static constexpr off_t kPacketCommandOff = 10; + +static constexpr uint8_t kDdmCommandSet = 199; +static constexpr uint8_t kDdmChunkCommand = 1; + static AdbConnectionState* gState; static bool IsDebuggingPossible() { @@ -116,6 +135,10 @@ AdbConnectionState::AdbConnectionState(const std::string& agent_name) shutting_down_(false), agent_loaded_(false), agent_listening_(false), + agent_has_socket_(false), + sent_agent_fds_(false), + performed_handshake_(false), + notified_ddm_active_(false), next_ddm_id_(1) { // Setup the addr. control_addr_.controlAddrUn.sun_family = AF_UNIX; @@ -245,10 +268,32 @@ static bool FlagsSet(int16_t data, int16_t flags) { } void AdbConnectionState::CloseFds() { - // Lock the write_event_fd so that concurrent PublishDdms will see that the connection is closed. - ScopedEventFdLock lk(adb_write_event_fd_); - // shutdown(adb_connection_socket_, SHUT_RDWR); - adb_connection_socket_.reset(); + { + // Lock the write_event_fd so that concurrent PublishDdms will see that the connection is + // closed. + ScopedEventFdLock lk(adb_write_event_fd_); + // shutdown(adb_connection_socket_, SHUT_RDWR); + adb_connection_socket_.reset(); + } + + // If we didn't load anything we will need to do the handshake again. + performed_handshake_ = false; + + // If the agent isn't loaded we might need to tell ddms code the connection is closed. + if (!agent_loaded_ && notified_ddm_active_) { + NotifyDdms(/*active*/false); + } +} + +void AdbConnectionState::NotifyDdms(bool active) { + art::ScopedObjectAccess soa(art::Thread::Current()); + DCHECK_NE(notified_ddm_active_, active); + notified_ddm_active_ = active; + if (active) { + art::Dbg::DdmConnected(); + } else { + art::Dbg::DdmDisconnected(); + } } uint32_t AdbConnectionState::NextDdmId() { @@ -257,6 +302,13 @@ uint32_t AdbConnectionState::NextDdmId() { } void AdbConnectionState::PublishDdmData(uint32_t type, const art::ArrayRef<const uint8_t>& data) { + SendDdmPacket(NextDdmId(), DdmPacketType::kCmd, type, data); +} + +void AdbConnectionState::SendDdmPacket(uint32_t id, + DdmPacketType packet_type, + uint32_t type, + art::ArrayRef<const uint8_t> data) { // Get the write_event early to fail fast. ScopedEventFdLock lk(adb_write_event_fd_); if (adb_connection_socket_ == -1) { @@ -276,7 +328,7 @@ void AdbConnectionState::PublishDdmData(uint32_t type, const art::ArrayRef<const kJDWPHeaderLen // jdwp command packet size + sizeof(uint32_t) // Type + sizeof(uint32_t); // length - std::array<uint8_t, kDdmPacketHeaderSize> pkt; + alignas(sizeof(uint32_t)) std::array<uint8_t, kDdmPacketHeaderSize> pkt; uint8_t* pkt_data = pkt.data(); // Write the length first. @@ -284,22 +336,35 @@ void AdbConnectionState::PublishDdmData(uint32_t type, const art::ArrayRef<const pkt_data += sizeof(uint32_t); // Write the id next; - *reinterpret_cast<uint32_t*>(pkt_data) = htonl(NextDdmId()); + *reinterpret_cast<uint32_t*>(pkt_data) = htonl(id); pkt_data += sizeof(uint32_t); // next the flags. (0 for cmd packet because DDMS). - *(pkt_data++) = 0; - // Now the cmd-set - *(pkt_data++) = kJDWPDdmCmdSet; - // Now the command - *(pkt_data++) = kJDWPDdmCmd; + *(pkt_data++) = static_cast<uint8_t>(packet_type); + switch (packet_type) { + case DdmPacketType::kCmd: { + // Now the cmd-set + *(pkt_data++) = kJDWPDdmCmdSet; + // Now the command + *(pkt_data++) = kJDWPDdmCmd; + break; + } + case DdmPacketType::kReply: { + // This is the error code bytes which are all 0 + *(pkt_data++) = 0; + *(pkt_data++) = 0; + } + } + // These are at unaligned addresses so we need to do them manually. // now the type. - *reinterpret_cast<uint32_t*>(pkt_data) = htonl(type); + uint32_t net_type = htonl(type); + memcpy(pkt_data, &net_type, sizeof(net_type)); pkt_data += sizeof(uint32_t); // Now the data.size() - *reinterpret_cast<uint32_t*>(pkt_data) = htonl(data.size()); + uint32_t net_len = htonl(data.size()); + memcpy(pkt_data, &net_len, sizeof(net_len)); pkt_data += sizeof(uint32_t); static uint32_t constexpr kIovSize = 2; @@ -327,17 +392,16 @@ void AdbConnectionState::PublishDdmData(uint32_t type, const art::ArrayRef<const } } -void AdbConnectionState::SendAgentFds() { - // TODO +void AdbConnectionState::SendAgentFds(bool require_handshake) { DCHECK(!sent_agent_fds_); - char dummy = '!'; + const char* message = require_handshake ? kPerformHandshakeMessage : kSkipHandshakeMessage; union { cmsghdr cm; char buffer[CMSG_SPACE(dt_fd_forward::FdSet::kDataLength)]; } cm_un; iovec iov; - iov.iov_base = &dummy; - iov.iov_len = 1; + iov.iov_base = const_cast<char*>(message); + iov.iov_len = strlen(message) + 1; msghdr msg; msg.msg_name = nullptr; @@ -492,6 +556,7 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { return; } while (!shutting_down_ && control_sock_ != -1) { + bool should_listen_on_connection = !agent_has_socket_ && !sent_agent_fds_; struct pollfd pollfds[4] = { { sleep_event_fd_, POLLIN, 0 }, // -1 as an fd causes it to be ignored by poll @@ -501,8 +566,8 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { { (adb_connection_socket_ == -1 ? control_sock_ : -1), POLLIN | POLLRDHUP, 0 }, // if we have not loaded the agent either the adb_connection_socket_ is -1 meaning we don't // have a real connection yet or the socket through adb needs to be listened to for incoming - // data that the agent can handle. - { ((!agent_has_socket_ && !sent_agent_fds_) ? adb_connection_socket_ : -1), POLLIN, 0 } + // data that the agent or this plugin can handle. + { should_listen_on_connection ? adb_connection_socket_ : -1, POLLIN | POLLRDHUP, 0 } }; int res = TEMP_FAILURE_RETRY(poll(pollfds, 4, -1)); if (res < 0) { @@ -528,7 +593,7 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { if (memcmp(kListenStartMessage, buf, sizeof(kListenStartMessage)) == 0) { agent_listening_ = true; if (adb_connection_socket_ != -1) { - SendAgentFds(); + SendAgentFds(/*require_handshake*/ !performed_handshake_); } } else if (memcmp(kListenEndMessage, buf, sizeof(kListenEndMessage)) == 0) { agent_listening_ = false; @@ -538,6 +603,8 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { } else if (memcmp(kAcceptMessage, buf, sizeof(kAcceptMessage)) == 0) { agent_has_socket_ = true; sent_agent_fds_ = false; + // We will only ever do the handshake once so reset this. + performed_handshake_ = false; } else { LOG(ERROR) << "Unknown message received from debugger! '" << std::string(buf) << "'"; } @@ -566,7 +633,9 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { } if (maybe_send_fds && agent_loaded_ && agent_listening_) { VLOG(jdwp) << "Sending fds as soon as we received them."; - SendAgentFds(); + // The agent was already loaded so this must be after a disconnection. Therefore have the + // transport perform the handshake. + SendAgentFds(/*require_handshake*/ true); } } else if (FlagsSet(control_sock_poll.revents, POLLRDHUP)) { // The other end of the adb connection just dropped it. @@ -578,27 +647,15 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { } else if (FlagsSet(adb_socket_poll.revents, POLLIN)) { DCHECK(!agent_has_socket_); if (!agent_loaded_) { - DCHECK(!agent_listening_); - // TODO Should we check in some other way if we are userdebug/eng? - CHECK(art::Dbg::IsJdwpAllowed()); - // Load the agent now! - self->AssertNoPendingException(); - art::Runtime::Current()->AttachAgent(/* JNIEnv* */ nullptr, - MakeAgentArg(), - /* classloader */ nullptr, - /*allow_non_debuggable_tooling*/ true); - if (self->IsExceptionPending()) { - LOG(ERROR) << "Failed to load agent " << agent_name_; - art::ScopedObjectAccess soa(self); - self->GetException()->Dump(); - self->ClearException(); - return; - } - agent_loaded_ = true; + HandleDataWithoutAgent(self); } else if (agent_listening_ && !sent_agent_fds_) { VLOG(jdwp) << "Sending agent fds again on data."; - SendAgentFds(); + // Agent was already loaded so it can deal with the handshake. + SendAgentFds(/*require_handshake*/ true); } + } else if (FlagsSet(adb_socket_poll.revents, POLLRDHUP)) { + DCHECK(!agent_has_socket_); + CloseFds(); } else { VLOG(jdwp) << "Woke up poll without anything to do!"; } @@ -606,10 +663,175 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { } } +static uint32_t ReadUint32AndAdvance(/*in-out*/uint8_t** in) { + uint32_t res; + memcpy(&res, *in, sizeof(uint32_t)); + *in = (*in) + sizeof(uint32_t); + return ntohl(res); +} + +void AdbConnectionState::HandleDataWithoutAgent(art::Thread* self) { + DCHECK(!agent_loaded_); + DCHECK(!agent_listening_); + // TODO Should we check in some other way if we are userdebug/eng? + CHECK(art::Dbg::IsJdwpAllowed()); + // We try to avoid loading the agent which is expensive. First lets just perform the handshake. + if (!performed_handshake_) { + PerformHandshake(); + return; + } + // Read the packet header to figure out if it is one we can handle. We only 'peek' into the stream + // to see if it's one we can handle. This doesn't change the state of the socket. + alignas(sizeof(uint32_t)) uint8_t packet_header[kPacketHeaderLen]; + ssize_t res = TEMP_FAILURE_RETRY(recv(adb_connection_socket_.get(), + packet_header, + sizeof(packet_header), + MSG_PEEK)); + // We want to be very careful not to change the socket state until we know we succeeded. This will + // let us fall-back to just loading the agent and letting it deal with everything. + if (res <= 0) { + // Close the socket. We either hit EOF or an error. + if (res < 0) { + PLOG(ERROR) << "Unable to peek into adb socket due to error. Closing socket."; + } + CloseFds(); + return; + } else if (res < static_cast<int>(kPacketHeaderLen)) { + LOG(ERROR) << "Unable to peek into adb socket. Loading agent to handle this. Only read " << res; + AttachJdwpAgent(self); + return; + } + uint32_t full_len = ntohl(*reinterpret_cast<uint32_t*>(packet_header + kPacketSizeOff)); + uint32_t pkt_id = ntohl(*reinterpret_cast<uint32_t*>(packet_header + kPacketIdOff)); + uint8_t pkt_cmd_set = packet_header[kPacketCommandSetOff]; + uint8_t pkt_cmd = packet_header[kPacketCommandOff]; + if (pkt_cmd_set != kDdmCommandSet || + pkt_cmd != kDdmChunkCommand || + full_len < kPacketHeaderLen) { + VLOG(jdwp) << "Loading agent due to jdwp packet that cannot be handled by adbconnection."; + AttachJdwpAgent(self); + return; + } + uint32_t avail = -1; + res = TEMP_FAILURE_RETRY(ioctl(adb_connection_socket_.get(), FIONREAD, &avail)); + if (res < 0) { + PLOG(ERROR) << "Failed to determine amount of readable data in socket! Closing connection"; + CloseFds(); + return; + } else if (avail < full_len) { + LOG(WARNING) << "Unable to handle ddm command in adbconnection due to insufficent data. " + << "Expected " << full_len << " bytes but only " << avail << " are readable. " + << "Loading jdwp agent to deal with this."; + AttachJdwpAgent(self); + return; + } + // Actually read the data. + std::vector<uint8_t> full_pkt; + full_pkt.resize(full_len); + res = TEMP_FAILURE_RETRY(recv(adb_connection_socket_.get(), full_pkt.data(), full_len, 0)); + if (res < 0) { + PLOG(ERROR) << "Failed to recv data from adb connection. Closing connection"; + CloseFds(); + return; + } + DCHECK_EQ(memcmp(full_pkt.data(), packet_header, sizeof(packet_header)), 0); + size_t data_size = full_len - kPacketHeaderLen; + if (data_size < (sizeof(uint32_t) * 2)) { + // This is an error (the data isn't long enough) but to match historical behavior we need to + // ignore it. + return; + } + uint8_t* ddm_data = full_pkt.data() + kPacketHeaderLen; + uint32_t ddm_type = ReadUint32AndAdvance(&ddm_data); + uint32_t ddm_len = ReadUint32AndAdvance(&ddm_data); + if (ddm_len > data_size - (2 * sizeof(uint32_t))) { + // This is an error (the data isn't long enough) but to match historical behavior we need to + // ignore it. + return; + } + + if (!notified_ddm_active_) { + NotifyDdms(/*active*/ true); + } + uint32_t reply_type; + std::vector<uint8_t> reply; + if (!art::Dbg::DdmHandleChunk(self->GetJniEnv(), + ddm_type, + art::ArrayRef<const jbyte>(reinterpret_cast<const jbyte*>(ddm_data), + ddm_len), + /*out*/&reply_type, + /*out*/&reply)) { + // To match historical behavior we don't send any response when there is no data to reply with. + return; + } + SendDdmPacket(pkt_id, + DdmPacketType::kReply, + reply_type, + art::ArrayRef<const uint8_t>(reply)); +} + +void AdbConnectionState::PerformHandshake() { + CHECK(!performed_handshake_); + // Check to make sure we are able to read the whole handshake. + uint32_t avail = -1; + int res = TEMP_FAILURE_RETRY(ioctl(adb_connection_socket_.get(), FIONREAD, &avail)); + if (res < 0 || avail < sizeof(kJdwpHandshake)) { + if (res < 0) { + PLOG(ERROR) << "Failed to determine amount of readable data for handshake!"; + } + LOG(WARNING) << "Closing connection to broken client."; + CloseFds(); + return; + } + // Perform the handshake. + char handshake_msg[sizeof(kJdwpHandshake)]; + res = TEMP_FAILURE_RETRY(recv(adb_connection_socket_.get(), + handshake_msg, + sizeof(handshake_msg), + MSG_DONTWAIT)); + if (res < static_cast<int>(sizeof(kJdwpHandshake)) || + strncmp(handshake_msg, kJdwpHandshake, sizeof(kJdwpHandshake)) != 0) { + if (res < 0) { + PLOG(ERROR) << "Failed to read handshake!"; + } + LOG(WARNING) << "Handshake failed!"; + CloseFds(); + return; + } + // Send the handshake back. + res = TEMP_FAILURE_RETRY(send(adb_connection_socket_.get(), + kJdwpHandshake, + sizeof(kJdwpHandshake), + 0)); + if (res < static_cast<int>(sizeof(kJdwpHandshake))) { + PLOG(ERROR) << "Failed to send jdwp-handshake response."; + CloseFds(); + return; + } + performed_handshake_ = true; +} + +void AdbConnectionState::AttachJdwpAgent(art::Thread* self) { + self->AssertNoPendingException(); + art::Runtime::Current()->AttachAgent(/* JNIEnv */ nullptr, + MakeAgentArg(), + /* classloader */ nullptr, + /*allow_non_debuggable_tooling*/ true); + if (self->IsExceptionPending()) { + LOG(ERROR) << "Failed to load agent " << agent_name_; + art::ScopedObjectAccess soa(self); + self->GetException()->Dump(); + self->ClearException(); + return; + } + agent_loaded_ = true; +} + std::string AdbConnectionState::MakeAgentArg() { // TODO Get this from something user settable? const std::string& opts = art::Runtime::Current()->GetJdwpOptions(); return agent_name_ + "=" + opts + (opts.empty() ? "" : ",") + + "ddm_already_active=" + (notified_ddm_active_ ? "y" : "n") + "," + "transport=dt_fd_forward,address=" + std::to_string(remote_agent_control_sock_); } diff --git a/adbconnection/adbconnection.h b/adbconnection/adbconnection.h index 28a5a05af3..e63a3b607d 100644 --- a/adbconnection/adbconnection.h +++ b/adbconnection/adbconnection.h @@ -24,6 +24,7 @@ #include "android-base/unique_fd.h" #include "base/mutex.h" +#include "base/array_ref.h" #include "runtime_callbacks.h" #include <sys/socket.h> @@ -56,6 +57,8 @@ struct AdbConnectionDebuggerController : public art::DebuggerControlCallback { AdbConnectionState* connection_; }; +enum class DdmPacketType : uint8_t { kReply = 0x80, kCmd = 0x00, }; + struct AdbConnectionDdmCallback : public art::DdmCallback { explicit AdbConnectionDdmCallback(AdbConnectionState* connection) : connection_(connection) {} @@ -94,10 +97,23 @@ class AdbConnectionState { android::base::unique_fd ReadFdFromAdb(); - void SendAgentFds(); + void SendAgentFds(bool require_handshake); void CloseFds(); + void HandleDataWithoutAgent(art::Thread* self); + + void PerformHandshake(); + + void AttachJdwpAgent(art::Thread* self); + + void NotifyDdms(bool active); + + void SendDdmPacket(uint32_t id, + DdmPacketType type, + uint32_t ddm_type, + art::ArrayRef<const uint8_t> data); + std::string agent_name_; AdbConnectionDebuggerController controller_; @@ -139,6 +155,10 @@ class AdbConnectionState { std::atomic<bool> sent_agent_fds_; + bool performed_handshake_; + + bool notified_ddm_active_; + std::atomic<uint32_t> next_ddm_id_; socklen_t control_addr_len_; diff --git a/dt_fd_forward/dt_fd_forward.cc b/dt_fd_forward/dt_fd_forward.cc index 1cf31a75a5..116cdf84ed 100644 --- a/dt_fd_forward/dt_fd_forward.cc +++ b/dt_fd_forward/dt_fd_forward.cc @@ -276,17 +276,16 @@ static void SendAcceptMessage(int fd) { TEMP_FAILURE_RETRY(send(fd, kAcceptMessage, sizeof(kAcceptMessage), MSG_EOR)); } -IOResult FdForwardTransport::ReceiveFdsFromSocket() { +IOResult FdForwardTransport::ReceiveFdsFromSocket(bool* do_handshake) { union { cmsghdr cm; uint8_t buffer[CMSG_SPACE(sizeof(FdSet))]; } msg_union; - // We don't actually care about the data. Only FDs. We need to have an iovec anyway to tell if we - // got the values or not though. - char dummy = '\0'; + // This lets us know if we need to do a handshake or not. + char message[128]; iovec iov; - iov.iov_base = &dummy; - iov.iov_len = sizeof(dummy); + iov.iov_base = message; + iov.iov_len = sizeof(message); msghdr msg; memset(&msg, 0, sizeof(msg)); @@ -307,8 +306,22 @@ IOResult FdForwardTransport::ReceiveFdsFromSocket() { return IOResult::kError; } FdSet out_fds = FdSet::ReadData(CMSG_DATA(cmsg)); - if (out_fds.read_fd_ < 0 || out_fds.write_fd_ < 0 || out_fds.write_lock_fd_ < 0) { + bool failed = false; + if (out_fds.read_fd_ < 0 || + out_fds.write_fd_ < 0 || + out_fds.write_lock_fd_ < 0) { DT_IO_ERROR("Received fds were invalid!"); + failed = true; + } else if (strcmp(kPerformHandshakeMessage, message) == 0) { + *do_handshake = true; + } else if (strcmp(kSkipHandshakeMessage, message) == 0) { + *do_handshake = false; + } else { + DT_IO_ERROR("Unknown message sent with fds."); + failed = true; + } + + if (failed) { if (out_fds.read_fd_ >= 0) { close(out_fds.read_fd_); } @@ -346,8 +359,9 @@ jdwpTransportError FdForwardTransport::Accept() { state_cv_.wait(lk); } + bool do_handshake = false; DCHECK_NE(listen_fd_.get(), -1); - if (ReceiveFdsFromSocket() != IOResult::kOk) { + if (ReceiveFdsFromSocket(&do_handshake) != IOResult::kOk) { CHECK(ChangeState(TransportState::kOpening, TransportState::kListening)); return ERR(IO_ERROR); } @@ -355,24 +369,27 @@ jdwpTransportError FdForwardTransport::Accept() { current_seq_num_++; // Moved to the opening state. - char handshake_recv[sizeof(kJdwpHandshake)]; - memset(handshake_recv, 0, sizeof(handshake_recv)); - IOResult res = ReadFullyWithoutChecks(handshake_recv, sizeof(handshake_recv)); - if (res != IOResult::kOk || - strncmp(handshake_recv, kJdwpHandshake, sizeof(kJdwpHandshake)) != 0) { - DT_IO_ERROR("Failed to read handshake"); - CHECK(ChangeState(TransportState::kOpening, TransportState::kListening)); - CloseFdsLocked(); - // Retry. - continue; - } - res = WriteFullyWithoutChecks(kJdwpHandshake, sizeof(kJdwpHandshake)); - if (res != IOResult::kOk) { - DT_IO_ERROR("Failed to write handshake"); - CHECK(ChangeState(TransportState::kOpening, TransportState::kListening)); - CloseFdsLocked(); - // Retry. - continue; + if (do_handshake) { + // Perform the handshake + char handshake_recv[sizeof(kJdwpHandshake)]; + memset(handshake_recv, 0, sizeof(handshake_recv)); + IOResult res = ReadFullyWithoutChecks(handshake_recv, sizeof(handshake_recv)); + if (res != IOResult::kOk || + strncmp(handshake_recv, kJdwpHandshake, sizeof(kJdwpHandshake)) != 0) { + DT_IO_ERROR("Failed to read handshake"); + CHECK(ChangeState(TransportState::kOpening, TransportState::kListening)); + CloseFdsLocked(); + // Retry. + continue; + } + res = WriteFullyWithoutChecks(kJdwpHandshake, sizeof(kJdwpHandshake)); + if (res != IOResult::kOk) { + DT_IO_ERROR("Failed to write handshake"); + CHECK(ChangeState(TransportState::kOpening, TransportState::kListening)); + CloseFdsLocked(); + // Retry. + continue; + } } break; } diff --git a/dt_fd_forward/dt_fd_forward.h b/dt_fd_forward/dt_fd_forward.h index 9303c59acd..07a574bfa0 100644 --- a/dt_fd_forward/dt_fd_forward.h +++ b/dt_fd_forward/dt_fd_forward.h @@ -105,7 +105,9 @@ class FdForwardTransport : public jdwpTransportEnv { bool ChangeState(TransportState old_state, TransportState new_state); // REQUIRES(state_mutex_); - IOResult ReceiveFdsFromSocket(); + // Gets the fds from the server side. do_handshake returns whether the transport can skip the + // jdwp handshake. + IOResult ReceiveFdsFromSocket(/*out*/bool* do_handshake); IOResult WriteFully(const void* data, size_t ndata); // REQUIRES(!state_mutex_); IOResult WriteFullyWithoutChecks(const void* data, size_t ndata); // REQUIRES(state_mutex_); diff --git a/dt_fd_forward/export/fd_transport.h b/dt_fd_forward/export/fd_transport.h index 245f0c2275..144ac5c6ec 100644 --- a/dt_fd_forward/export/fd_transport.h +++ b/dt_fd_forward/export/fd_transport.h @@ -47,6 +47,12 @@ struct FdSet { } }; +// Sent with the file descriptors if the transport should not skip waiting for the handshake. +static constexpr char kPerformHandshakeMessage[] = "HANDSHAKE:REQD"; + +// Sent with the file descriptors if the transport can skip waiting for the handshake. +static constexpr char kSkipHandshakeMessage[] = "HANDSHAKE:SKIP"; + // This message is sent over the fd associated with the transport when we are listening for fds. static constexpr char kListenStartMessage[] = "dt_fd_forward:START-LISTEN"; diff --git a/tools/dt_fds_forward.py b/tools/dt_fds_forward.py index 516b7fef96..1f9c41fc26 100755 --- a/tools/dt_fds_forward.py +++ b/tools/dt_fds_forward.py @@ -34,10 +34,11 @@ import subprocess import sys import time -LISTEN_START_MESSAGE = b"dt_fd_forward:START-LISTEN\x00" -LISTEN_END_MESSAGE = b"dt_fd_forward:END-LISTEN\x00" -ACCEPTED_MESSAGE = b"dt_fd_forward:ACCEPTED\x00" -CLOSE_MESSAGE = b"dt_fd_forward:CLOSING\x00" +NEED_HANDSHAKE_MESSAGE = b"HANDSHAKE:REQD\x00" +LISTEN_START_MESSAGE = b"dt_fd_forward:START-LISTEN\x00" +LISTEN_END_MESSAGE = b"dt_fd_forward:END-LISTEN\x00" +ACCEPTED_MESSAGE = b"dt_fd_forward:ACCEPTED\x00" +CLOSE_MESSAGE = b"dt_fd_forward:CLOSING\x00" libc = ctypes.cdll.LoadLibrary("libc.so.6") def eventfd(init_val, flags): @@ -70,7 +71,7 @@ def send_fds(sock, remote_read, remote_write, remote_event): """ Send the three fds over the given socket. """ - sock.sendmsg([b"!"], # We don't actually care what we send here. + sock.sendmsg([NEED_HANDSHAKE_MESSAGE], # We want the transport to handle the handshake. [(socket.SOL_SOCKET, # Send over socket. socket.SCM_RIGHTS, # Payload is file-descriptor array array.array('i', [remote_read, remote_write, remote_event]))]) |