summaryrefslogtreecommitdiff
path: root/stream-servers/RenderChannel.h
blob: 42f8e5abcdd6dc2aedd0d76c48356124787861ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// 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.
#pragma once

#include "base/EnumFlags.h"
#include "base/BufferQueue.h"
#include "base/SmallVector.h"
#include "base/Stream.h"

#include <functional>
#include <memory>

namespace emugl {

// Turn the RenderChannel::State enum into flags.
using namespace ::android::base::EnumFlags;

// RenderChannel - For each guest-to-host renderer connection, this provides
// an interface for the guest side to interact with the corresponding renderer
// thread on the host. Its main purpose is to send and receive wire protocol
// bytes in an asynchronous way (compatible with Android pipes).
//
// Usage is the following:
//    1) Get an instance pointer through a dedicated Renderer function
//       (e.g. RendererImpl::createRenderChannel()).
//
//    2) Call setEventCallback() to indicate which callback should be called
//       when the channel's state has changed due to a host thread event.
//
class RenderChannel {
public:
    // A type used to pass byte packets between the guest and the
    // RenderChannel instance. Experience has shown that using a
    // SmallFixedVector<char, N> instance instead of a std::vector<char>
    // avoids a lot of un-necessary heap allocations. The current size
    // of 512 was selected after profiling existing traffic, including
    // the one used in protocol-heavy benchmark like Antutu3D.
    using Buffer = android::base::SmallFixedVector<char, 512>;

    // Bit-flags for the channel state.
    // |CanRead| means there is data from the host to read.
    // |CanWrite| means there is room to send data to the host.
    // |Stopped| means the channel was stopped.
    enum class State {
        // Can't use None here, some system header declares it as a macro.
        Empty = 0,
        CanRead = 1 << 0,
        CanWrite = 1 << 1,
        Stopped = 1 << 2,
    };

    using IoResult = android::base::BufferQueueResult;
    using Duration = uint64_t;

    // Type of a callback used to tell the guest when the RenderChannel
    // state changes. Used by setEventCallback(). The parameter contains
    // the State bits matching the event, i.e. it is the logical AND of
    // the last value passed to setWantedEvents() and the current
    // RenderChannel state.
    using EventCallback = std::function<void(State)>;

    // Sets a single (!) callback that is called when the channel state's
    // changes due to an event *from* *the* *host* only. |callback| is a
    // guest-provided callback that will be called from the host renderer
    // thread, not the guest one.
    virtual void setEventCallback(EventCallback&& callback) = 0;

    // Used to indicate which i/o events the guest wants to be notified
    // through its StateChangeCallback. |state| must be a combination of
    // State::CanRead or State::CanWrite only. This will *not* call the
    // callback directly since this happens in the guest thread.
    virtual void setWantedEvents(State state) = 0;

    // Get the current state flags.
    virtual State state() const = 0;

    // Try to writes the data in |buffer| into the channel. On success,
    // return IoResult::Ok and moves |buffer|. On failure, return
    // IoResult::TryAgain if the channel was full, or IoResult::Error
    // if it is stopped.
    virtual IoResult tryWrite(Buffer&& buffer) = 0;

    // Try to read data from the channel. On success, return IoResult::Ok and
    // sets |*buffer| to contain the data. On failure, return
    // IoResult::TryAgain if the channel was empty, or IoResult::Error if
    // it was stopped.
    virtual IoResult tryRead(Buffer* buffer) = 0;

    // Try to read data from the channel. On success, return IoResult::Ok and
    // sets |*buffer| to contain the data. On failure, return IoResult::Error
    // if it was stopped. Returns IoResult::Timeout if we waited passed
    // waitUntilUs.
    virtual IoResult readBefore(Buffer* buffer, Duration waitUntilUs) = 0;

    // Abort all pending operations. Any following operation is a noop.
    // Once a channel is stopped, it cannot be re-started.
    virtual void stop() = 0;

    // Callback function when snapshotting the virtual machine.
    virtual void onSave(android::base::Stream* stream) = 0;

protected:
    ~RenderChannel() = default;
};

// Shared pointer to RenderChannel instance.
using RenderChannelPtr = std::shared_ptr<RenderChannel>;

}  // namespace emugl