1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "vsock_hwc"
18
19 #include "guest/hals/hwcomposer/cutf_cvm/vsocket_screen_view.h"
20
21 #include <cutils/properties.h>
22 #include <log/log.h>
23
24 #include "common/libs/device_config/device_config.h"
25
26 namespace cuttlefish {
27
VsocketScreenView()28 VsocketScreenView::VsocketScreenView()
29 : broadcast_thread_([this]() { BroadcastLoop(); }) {
30 GetScreenParameters();
31 // inner_buffer needs to be initialized after the final values of the screen
32 // parameters are set (either from the config server or default).
33 inner_buffer_ = std::vector<char>(buffer_size() * 8);
34 }
35
~VsocketScreenView()36 VsocketScreenView::~VsocketScreenView() {
37 running_ = false;
38 broadcast_thread_.join();
39 }
40
GetScreenParameters()41 void VsocketScreenView::GetScreenParameters() {
42 auto device_config = cuttlefish::DeviceConfig::Get();
43 if (!device_config) {
44 ALOGI(
45 "Failed to obtain device configuration from server, running in "
46 "headless mode");
47 // It is impossible to ensure host and guest agree on the screen parameters
48 // if these could not be read from the host configuration server. It's best
49 // to not attempt to send frames in this case.
50 running_ = false;
51 // Do a phony Broadcast to ensure the broadcaster thread exits.
52 Broadcast(-1);
53 return;
54 }
55 x_res_ = device_config->screen_x_res();
56 y_res_ = device_config->screen_y_res();
57 dpi_ = device_config->screen_dpi();
58 refresh_rate_ = device_config->screen_refresh_rate();
59 ALOGI("Received screen parameters: res=%dx%d, dpi=%d, freq=%d", x_res_,
60 y_res_, dpi_, refresh_rate_);
61 }
62
ConnectToScreenServer()63 bool VsocketScreenView::ConnectToScreenServer() {
64 auto vsock_frames_port = property_get_int64("ro.boot.vsock_frames_port", -1);
65 if (vsock_frames_port <= 0) {
66 ALOGI("No screen server configured, operating on headless mode");
67 return false;
68 }
69
70 screen_server_ = cuttlefish::SharedFD::VsockClient(
71 2, static_cast<unsigned int>(vsock_frames_port), SOCK_STREAM);
72 if (!screen_server_->IsOpen()) {
73 ALOGE("Unable to connect to screen server: %s", screen_server_->StrError());
74 return false;
75 }
76
77 return true;
78 }
79
BroadcastLoop()80 void VsocketScreenView::BroadcastLoop() {
81 auto connected = ConnectToScreenServer();
82 if (!connected) {
83 ALOGE(
84 "Broadcaster thread exiting due to no connection to screen server. "
85 "Compositions will occur, but frames won't be sent anywhere");
86 return;
87 }
88 int current_seq = 0;
89 int current_offset;
90 ALOGI("Broadcaster thread loop starting");
91 while (true) {
92 {
93 std::unique_lock<std::mutex> lock(mutex_);
94 while (running_ && current_seq == current_seq_) {
95 cond_var_.wait(lock);
96 }
97 if (!running_) {
98 ALOGI("Broadcaster thread exiting");
99 return;
100 }
101 current_offset = current_offset_;
102 current_seq = current_seq_;
103 }
104 int32_t size = buffer_size();
105 screen_server_->Write(&size, sizeof(size));
106 auto buff = static_cast<char*>(GetBuffer(current_offset));
107 while (size > 0) {
108 auto written = screen_server_->Write(buff, size);
109 if (written == -1) {
110 ALOGE("Broadcaster thread failed to write frame: %s", strerror(errno));
111 break;
112 }
113 size -= written;
114 buff += written;
115 }
116 }
117 }
118
Broadcast(int offset,const CompositionStats *)119 void VsocketScreenView::Broadcast(int offset, const CompositionStats*) {
120 std::lock_guard<std::mutex> lock(mutex_);
121 current_offset_ = offset;
122 current_seq_++;
123 cond_var_.notify_all();
124 }
125
GetBuffer(int buffer_id)126 void* VsocketScreenView::GetBuffer(int buffer_id) {
127 return &inner_buffer_[buffer_size() * buffer_id];
128 }
129
x_res() const130 int32_t VsocketScreenView::x_res() const { return x_res_; }
y_res() const131 int32_t VsocketScreenView::y_res() const { return y_res_; }
dpi() const132 int32_t VsocketScreenView::dpi() const { return dpi_; }
refresh_rate() const133 int32_t VsocketScreenView::refresh_rate() const { return refresh_rate_; }
134
num_buffers() const135 int VsocketScreenView::num_buffers() const {
136 return inner_buffer_.size() / buffer_size();
137 }
138
139 } // namespace cuttlefish
140