blob: db27b41e1ff4c96d20f581d8c9dfddca7243c1f5 [file] [log] [blame]
// Copyright (C) 2016 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 "RenderChannelImpl.h"
#include "android/base/synchronization/Lock.h"
#include <algorithm>
#include <utility>
#include <assert.h>
#include <string.h>
namespace emugl {
#define EMUGL_DEBUG_LEVEL 0
#include "emugl/common/debug.h"
using Buffer = RenderChannel::Buffer;
using IoResult = RenderChannel::IoResult;
using State = RenderChannel::State;
using AutoLock = android::base::AutoLock;
// These constants correspond to the capacities of buffer queues
// used by each RenderChannelImpl instance. Benchmarking shows that
// it's important to have a large queue for guest -> host transfers,
// but a much smaller one works for host -> guest ones.
static constexpr size_t kGuestToHostQueueCapacity = 1024U;
static constexpr size_t kHostToGuestQueueCapacity = 16U;
RenderChannelImpl::RenderChannelImpl()
: mLock(),
mFromGuest(kGuestToHostQueueCapacity, mLock),
mToGuest(kHostToGuestQueueCapacity, mLock) {
updateStateLocked();
}
void RenderChannelImpl::setEventCallback(EventCallback&& callback) {
mEventCallback = std::move(callback);
}
void RenderChannelImpl::setWantedEvents(State state) {
D("state=%d", (int)state);
AutoLock lock(mLock);
mWantedEvents |= state;
notifyStateChangeLocked();
}
RenderChannel::State RenderChannelImpl::state() const {
AutoLock lock(mLock);
return mState;
}
IoResult RenderChannelImpl::tryWrite(Buffer&& buffer) {
D("buffer size=%d", (int)buffer.size());
AutoLock lock(mLock);
auto result = mFromGuest.tryPushLocked(std::move(buffer));
updateStateLocked();
DD("mFromGuest.tryPushLocked() returned %d, state %d", (int)result,
(int)mState);
return result;
}
IoResult RenderChannelImpl::tryRead(Buffer* buffer) {
D("enter");
AutoLock lock(mLock);
auto result = mToGuest.tryPopLocked(buffer);
updateStateLocked();
DD("mToGuest.tryPopLocked() returned %d, buffer size %d, state %d",
(int)result, (int)buffer->size(), (int)mState);
return result;
}
void RenderChannelImpl::stop() {
D("enter");
AutoLock lock(mLock);
mFromGuest.closeLocked();
mToGuest.closeLocked();
}
bool RenderChannelImpl::writeToGuest(Buffer&& buffer) {
D("buffer size=%d", (int)buffer.size());
AutoLock lock(mLock);
IoResult result = mToGuest.pushLocked(std::move(buffer));
updateStateLocked();
DD("mToGuest.pushLocked() returned %d, state %d", (int)result, (int)mState);
notifyStateChangeLocked();
return result == IoResult::Ok;
}
IoResult RenderChannelImpl::readFromGuest(Buffer* buffer, bool blocking) {
D("enter");
AutoLock lock(mLock);
IoResult result;
if (blocking) {
result = mFromGuest.popLocked(buffer);
} else {
result = mFromGuest.tryPopLocked(buffer);
}
updateStateLocked();
DD("mFromGuest.%s() return %d, buffer size %d, state %d",
blocking ? "popLocked" : "tryPopLocked", (int)result,
(int)buffer->size(), (int)mState);
notifyStateChangeLocked();
return result;
}
void RenderChannelImpl::stopFromHost() {
D("enter");
AutoLock lock(mLock);
mFromGuest.closeLocked();
mToGuest.closeLocked();
mState |= State::Stopped;
notifyStateChangeLocked();
}
void RenderChannelImpl::updateStateLocked() {
State state = RenderChannel::State::Empty;
if (mToGuest.canPopLocked()) {
state |= State::CanRead;
}
if (mFromGuest.canPushLocked()) {
state |= State::CanWrite;
}
if (mToGuest.isClosedLocked()) {
state |= State::Stopped;
}
mState = state;
}
void RenderChannelImpl::notifyStateChangeLocked() {
State available = mState & mWantedEvents;
if (available != 0) {
D("callback with %d", (int)available);
mWantedEvents &= ~mState;
mEventCallback(available);
}
}
} // namespace emugl