blob: c0bd6af1a9017b7facff2ba80ad9bcdea51f80ca [file] [log] [blame]
// Copyright 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "PacketStreamTransport.h"
#include <stddef.h>
#include <type_traits>
#include <utility>
#include "aemu/base/logging/Log.h"
#include "android-qemu2-glue/netsim/PacketProtocol.h"
#include "netsim/startup.pb.h"
namespace android {
namespace qemu2 {
// #define DEBUG 2
/* set for very verbose debugging */
#ifndef DEBUG
#define DD(...) (void)0
#define DD_BUF(buf, len) (void)0
#else
#define DD(...) dinfo(__VA_ARGS__)
#define DD_BUF(buf, len) \
do { \
printf("packet-stream %s:", __func__); \
for (int x = 0; x < len; x++) { \
if (isprint((int)buf[x])) { \
printf("%c", buf[x]); \
} else { \
printf("[0x%02x]", 0xff & (int)buf[x]); \
} \
} \
} while (0); \
printf("\n");
#endif
PacketStreamerTransport::PacketStreamerTransport(
PacketStreamChardev* qemuDevice,
std::unique_ptr<PacketProtocol> serializer,
std::shared_ptr<grpc::Channel> channel,
ChannelFactory factory)
: mQemudevice(qemuDevice),
mStub(PacketStreamer::NewStub(channel)),
mSerializer(std::move(serializer)),
mChannelFactory(factory),
mQemuDeviceWriter([this](uint8_t* bytes, size_t size) {
DD("Writing %d bytest to qemu", size);
qemu_chr_be_write(&mQemudevice->parent, bytes, size);
}) {}
PacketStreamerTransport::~PacketStreamerTransport() {}
void PacketStreamerTransport::Read(const PacketResponse* received) {
mSerializer->forwardToQemu(received, mQemuDeviceWriter);
}
void PacketStreamerTransport::OnDone(const grpc::Status& s) {
mSerializer->connectionStateChange(
PacketProtocol::ConnectionStateChange::REMOTE_DISCONNECTED,
mQemuDeviceWriter);
mDone = true;
mAwaitCondition.notify_one();
if (mReconnect) {
auto channel = mChannelFactory();
if (!channel) {
auto info = mSerializer->chip_info();
dwarning("Unable to reconnect to packet streamer for device: %s",
info->name().c_str());
} else {
// replace the transport..
DD("Replacing transport");
auto transport = PacketStreamerTransport::create(
mQemudevice, std::move(mSerializer), channel,
mChannelFactory);
mQemudevice->transport = transport;
transport->start();
}
}
// No longer active..
DD("Goodbye kids! It was fun");
mMe.reset();
}
void PacketStreamerTransport::cancel() {
mReconnect = false;
// This will result in the scheduling of an OnDone callback.
// At that point we will notify the packet protocol of a state change.
mContext.TryCancel();
}
uint64_t PacketStreamerTransport::fromQemu(const uint8_t* buffer,
uint64_t bufferSize) {
auto packets = mSerializer->forwardToPacketStreamer(buffer, bufferSize);
writePackets(packets);
return bufferSize;
}
void PacketStreamerTransport::qemuConnected() {
auto packets = mSerializer->connectionStateChange(
PacketProtocol::ConnectionStateChange::QEMU_CONNECTED,
mQemuDeviceWriter);
writePackets(packets);
}
bool PacketStreamerTransport::await() {
std::unique_lock<std::mutex> l(mAwaitMutex);
mAwaitCondition.wait(l, [this] { return mDone; });
return mReconnect;
}
void PacketStreamerTransport::start() {
// I'm active! Update the self reference.
DD("Starting stream.");
mMe = shared_from_this();
// Setup async call
mStub->async()->StreamPackets(&mContext, this);
StartCall();
StartRead();
// Notify that we are connected, and send out the handshake packets
// (if any)
auto packets = mSerializer->connectionStateChange(
PacketProtocol::ConnectionStateChange::REMOTE_CONNECTED,
mQemuDeviceWriter);
writePackets(packets);
DD("Stream scheduled.");
}
void PacketStreamerTransport::writePackets(
const std::vector<PacketRequest>& packets) {
std::lock_guard<std::mutex> guard(mWriterMutex);
DD("Writing packets..");
for (const auto& packet : packets) {
Write(packet);
}
DD("Completed writing packets.");
}
std::shared_ptr<PacketStreamerTransport> PacketStreamerTransport::create(
PacketStreamChardev* qemuDevice,
std::unique_ptr<PacketProtocol> serializer,
std::shared_ptr<grpc::Channel> channel,
ChannelFactory factory) {
return std::shared_ptr<PacketStreamerTransport>(new PacketStreamerTransport(
qemuDevice, std::move(serializer), std::move(channel),
std::move(factory)));
}
} // namespace qemu2
} // namespace android