// Copy from file_utils, so we do not need to depend on libartbase. staticint DupCloexec(int fd) { #ifdefined(__linux__) return fcntl(fd, F_DUPFD_CLOEXEC, 0); #else return dup(fd); #endif
}
jdwpTransportError FdForwardTransport::StopListening() {
std::lock_guard<std::mutex> lk(state_mutex_); if (listen_fd_ != -1) {
SendListenEndMessage(listen_fd_);
} // Don't close the listen_fd_ since we might need it for later calls to listen. if (ChangeState(TransportState::kListening, TransportState::kClosed) ||
state_ == TransportState::kOpen) {
listen_fd_.reset();
} return OK;
}
// Last error message.
thread_local std::string global_last_error_;
IOResult FdForwardTransport::ReadUpToMax(void* data, size_t ndata, /*out*/size_t* read_amount) {
CHECK_GE(read_fd_.get(), 0); int avail; int res = TEMP_FAILURE_RETRY(ioctl(read_fd_, FIONREAD, &avail)); if (res < 0) {
DT_IO_ERROR("Failed ioctl(read_fd_, FIONREAD, &avail)"); return IOResult::kError;
}
size_t to_read = std::min(static_cast<size_t>(avail), ndata);
*read_amount = to_read; if (*read_amount == 0) { // Check if the read would cause an EOF. struct pollfd pollfd = { read_fd_, POLLRDHUP, 0 };
res = TEMP_FAILURE_RETRY(poll(&pollfd, /*nfds*/1, /*timeout*/0)); if (res < 0 || (pollfd.revents & POLLERR) == POLLERR) {
DT_IO_ERROR("Failed poll on read fd."); return IOResult::kError;
} return ((pollfd.revents & (POLLRDHUP | POLLHUP)) == 0) ? IOResult::kOk : IOResult::kEOF;
}
return ReadFullyWithoutChecks(data, to_read);
}
IOResult FdForwardTransport::ReadFully(void* data, size_t ndata) {
uint64_t seq_num = current_seq_num_;
size_t nbytes = 0; while (nbytes < ndata) {
size_t read_len; struct pollfd pollfds[2];
{
std::lock_guard<std::mutex> lk(state_mutex_); // Operations in this block must not cause an unbounded pause. if (state_ != TransportState::kOpen || seq_num != current_seq_num_) { // Async-close occurred! return IOResult::kInterrupt;
} else {
CHECK_GE(read_fd_.get(), 0);
}
IOResult res = ReadUpToMax(reinterpret_cast<uint8_t*>(data) + nbytes,
ndata - nbytes, /*out*/&read_len); if (res != IOResult::kOk) { return res;
} else {
nbytes += read_len;
}
pollfds[0] = { read_fd_, POLLRDHUP | POLLIN, 0 };
pollfds[1] = { wakeup_fd_, POLLIN, 0 };
} if (read_len == 0) { // No more data. Sleep without locks until more is available. We don't actually check for any // errors since possible ones are (1) the read_fd_ is closed or wakeup happens which are both // fine since the wakeup_fd_ or the poll failing will wake us up. int poll_res = TEMP_FAILURE_RETRY(poll(pollfds, 2, -1)); if (poll_res < 0) {
DT_IO_ERROR("Failed to poll!");
} // Clear the wakeup_fd regardless.
uint64_t val; int unused = TEMP_FAILURE_RETRY(read(wakeup_fd_, &val, sizeof(val)));
DCHECK(unused == sizeof(val) || errno == EAGAIN); if (poll_res < 0) { return IOResult::kError;
}
}
} return IOResult::kOk;
}
// A helper that allows us to lock the eventfd 'fd'. class ScopedEventFdLock { public: explicit ScopedEventFdLock(const android::base::unique_fd& fd) : fd_(fd), data_(0) {
TEMP_FAILURE_RETRY(read(fd_, &data_, sizeof(data_)));
}
IOResult FdForwardTransport::ReceiveFdsFromSocket(bool* do_handshake) { union {
cmsghdr cm;
uint8_t buffer[CMSG_SPACE(sizeof(FdSet))];
} msg_union; // This lets us know if we need to do a handshake or not. char message[128];
iovec iov;
iov.iov_base = message;
iov.iov_len = sizeof(message);
// We got the fds. Send ack.
close_notify_fd_.reset(DupCloexec(listen_fd_));
SendAcceptMessage(close_notify_fd_);
return IOResult::kOk;
}
// Accept the connection. Note that we match the behavior of other transports which is to just close // the connection and try again if we get a bad handshake.
jdwpTransportError FdForwardTransport::Accept() { // TODO Work with timeouts. while (true) {
std::unique_lock<std::mutex> lk(state_mutex_); while (!ChangeState(TransportState::kListening, TransportState::kOpening)) { if (state_ == TransportState::kClosed ||
state_ == TransportState::kOpen) { return ERR(ILLEGAL_STATE);
}
state_cv_.wait(lk);
}
// Actually close the fds associated with this transport. void FdForwardTransport::CloseFdsLocked() { // We have a different set of fd's now. Increase the seq number.
current_seq_num_++;
// All access to these is locked under the state_mutex_ so we are safe to close these.
{
ScopedEventFdLock sefdl(write_lock_fd_); if (close_notify_fd_ >= 0) {
SendClosingMessage(close_notify_fd_);
}
close_notify_fd_.reset();
read_fd_.reset();
write_fd_.reset();
close_notify_fd_.reset();
}
write_lock_fd_.reset();
// Send a wakeup in case we have any in-progress reads/writes.
uint64_t data = 1;
TEMP_FAILURE_RETRY(write(wakeup_fd_, &data, sizeof(data)));
}
jdwpTransportError FdForwardTransport::Close() {
std::lock_guard<std::mutex> lk(state_mutex_);
jdwpTransportError res =
ChangeState(TransportState::kOpen, TransportState::kClosed) ? OK : ERR(ILLEGAL_STATE); // Send a wakeup after changing the state even if nothing actually happened.
uint64_t data = 1;
TEMP_FAILURE_RETRY(write(wakeup_fd_, &data, sizeof(data))); if (res == OK) {
CloseFdsLocked();
} return res;
}
// A helper class to read and parse the JDWP packet. class PacketReader { public:
PacketReader(FdForwardTransport* transport, jdwpPacket* pkt)
: transport_(transport),
pkt_(pkt),
is_eof_(false),
is_err_(false) {} bool ReadFully() { // Zero out.
memset(pkt_, 0, sizeof(jdwpPacket));
int32_t len = ReadInt32(); // read len if (is_err_) { returnfalse;
} elseif (is_eof_) { returntrue;
} elseif (len < 11) {
transport_->DT_IO_ERROR("Packet with len < 11 received!"); returnfalse;
}
pkt_->type.cmd.len = len;
pkt_->type.cmd.id = ReadInt32();
pkt_->type.cmd.flags = ReadByte(); if (is_err_) { returnfalse;
} elseif (is_eof_) { returntrue;
} elseif ((pkt_->type.reply.flags & JDWPTRANSPORT_FLAGS_REPLY) == JDWPTRANSPORT_FLAGS_REPLY) {
ReadReplyPacket();
} else {
ReadCmdPacket();
} return !is_err_;
}
// `produceVal` is a function which produces the success value. It'd be a bit // syntactically simpler to simply take a `T success`, but doing so invites // the possibility of operating on uninitalized data, since we often want to // either return the failure value, or return a massaged version of what we // read off the wire, e.g., // // ``` // IOResult res = transport->ReadFully(&out, sizeof(out)); // return HandleResult(res, fail, [&] { return SomeTransform(&out); }); // ``` template <typename T, typename Fn>
T HandleResult(IOResult res, T fail, Fn produceVal) { switch (res) { case IOResult::kError:
is_err_ = true; return fail; case IOResult::kOk: return produceVal(); case IOResult::kEOF:
is_eof_ = true;
pkt_->type.cmd.len = 0; return fail; case IOResult::kInterrupt:
transport_->DT_IO_ERROR("Failed to read, concurrent close!");
is_err_ = true; return fail;
}
}
jbyte* ReadRemaining() { if (is_eof_ || is_err_) { return nullptr;
}
jbyte* out = nullptr;
jint rem = pkt_->type.cmd.len - 11;
CHECK_GE(rem, 0); if (rem == 0) { return nullptr;
} else {
out = reinterpret_cast<jbyte*>(transport_->Alloc(rem));
IOResult res = transport_->ReadFully(out, rem);
jbyte* ret = HandleResult(res, static_cast<jbyte*>(nullptr), [&] { return out; }); if (ret != out) {
transport_->Free(out);
} return ret;
}
}
// A class that writes a packet to the transport. class PacketWriter { public:
PacketWriter(FdForwardTransport* transport, const jdwpPacket* pkt)
: transport_(transport), pkt_(pkt), data_() {}
static jdwpTransportError ParseAddress(const std::string& addr, /*out*/int* listen_sock) { if (!android::base::ParseInt(addr.c_str(), listen_sock) || *listen_sock < 0) {
LOG(ERROR) << "address format is <fd_num> not " << addr; return ERR(ILLEGAL_ARGUMENT);
} return OK;
}
class JdwpTransportFunctions { public: static jdwpTransportError GetCapabilities([[maybe_unused]] jdwpTransportEnv* env, /*out*/ JDWPTransportCapabilities* capabilities_ptr) { // We don't support any of the optional capabilities (can_timeout_attach, can_timeout_accept, // can_timeout_handshake) so just return a zeroed capabilities ptr. // TODO We should maybe support these timeout options.
memset(capabilities_ptr, 0, sizeof(JDWPTransportCapabilities)); return OK;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.