1 /* 2 * Copyright (C) 2019 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 #include "host/frontend/vnc_server/screen_connector.h" 18 19 #include <atomic> 20 #include <condition_variable> 21 22 #include <gflags/gflags.h> 23 24 #include <common/vsoc/lib/screen_region_view.h> 25 #include <host/libs/config/cuttlefish_config.h> 26 #include "host/frontend/vnc_server/vnc_utils.h" 27 28 DEFINE_int32(frame_server_fd, -1, ""); 29 30 namespace cvd { 31 namespace vnc { 32 33 namespace { 34 class VSoCScreenConnector : public ScreenConnector { 35 public: WaitForNewFrameSince(std::uint32_t * seq_num)36 int WaitForNewFrameSince(std::uint32_t* seq_num) override { 37 if (!screen_view_) return -1; 38 return screen_view_->WaitForNewFrameSince(seq_num); 39 } 40 GetBuffer(int buffer_idx)41 void* GetBuffer(int buffer_idx) override { 42 if (!screen_view_) return nullptr; 43 return screen_view_->GetBuffer(buffer_idx); 44 } 45 46 private: 47 vsoc::screen::ScreenRegionView* screen_view_ = 48 vsoc::screen::ScreenRegionView::GetInstance(vsoc::GetDomain().c_str()); 49 }; 50 51 // TODO(b/128852363): Substitute with one based on memory shared with the 52 // wayland mock 53 class SocketBasedScreenConnector : public ScreenConnector { 54 public: SocketBasedScreenConnector(vsoc::CuttlefishConfig * config)55 SocketBasedScreenConnector(vsoc::CuttlefishConfig* config) : config_(config) { 56 screen_server_thread_ = std::thread([this]() { ServerLoop(); }); 57 } 58 WaitForNewFrameSince(std::uint32_t * seq_num)59 int WaitForNewFrameSince(std::uint32_t* seq_num) override { 60 std::unique_lock<std::mutex> lock(new_frame_mtx_); 61 while (seq_num_ == *seq_num) { 62 new_frame_cond_var_.wait(lock); 63 } 64 return newest_buffer_; 65 } 66 GetBuffer(int buffer_idx)67 void* GetBuffer(int buffer_idx) override { 68 if (buffer_idx < 0) return nullptr; 69 buffer_idx %= NUM_BUFFERS_; 70 return &buffer_[buffer_idx * ScreenSizeInBytes()]; 71 } 72 73 private: 74 static constexpr int NUM_BUFFERS_ = 4; 75 ServerLoop()76 void ServerLoop() { 77 if (FLAGS_frame_server_fd < 0) { 78 LOG(FATAL) << "Invalid file descriptor: " << FLAGS_frame_server_fd; 79 return; 80 } 81 auto server = SharedFD::Dup(FLAGS_frame_server_fd); 82 close(FLAGS_frame_server_fd); 83 if (!server->IsOpen()) { 84 LOG(FATAL) << "Unable to dup screen server: " << server->StrError(); 85 return; 86 } 87 88 int current_buffer = 0; 89 90 while (1) { 91 auto conn = SharedFD::Accept(*server); 92 while (conn->IsOpen()) { 93 SendScreenParameters(conn); 94 95 int32_t size = 0; 96 conn->Read(&size, sizeof(size)); 97 auto buff = reinterpret_cast<uint8_t*>(GetBuffer(current_buffer)); 98 while (size > 0) { 99 auto read = conn->Read(buff, size); 100 if (read < 0) { 101 LOG(ERROR) << "Failed to read from hwcomposer: " 102 << conn->StrError(); 103 return; 104 } 105 size -= read; 106 buff += read; 107 } 108 BroadcastNewFrame(current_buffer); 109 current_buffer = (current_buffer + 1) % NUM_BUFFERS_; 110 } 111 } 112 } 113 SendScreenParameters(SharedFD conn) const114 void SendScreenParameters(SharedFD conn) const { 115 // TODO(b/128842613): Send this info from the configuration server 116 int32_t screen_params[4]; 117 screen_params[0] = config_->x_res(); 118 screen_params[1] = config_->y_res(); 119 screen_params[2] = config_->dpi(); 120 screen_params[3] = config_->refresh_rate_hz(); 121 int buff_size = sizeof(screen_params); 122 int res = conn->Write(screen_params, buff_size); 123 if (res != buff_size) { 124 LOG(FATAL) 125 << "Unable to send full screen parameters to the hwcomposer (" 126 << res << "): " << conn->StrError(); 127 } 128 } 129 BroadcastNewFrame(int buffer_idx)130 void BroadcastNewFrame(int buffer_idx) { 131 { 132 std::lock_guard<std::mutex> lock(new_frame_mtx_); 133 seq_num_++; 134 newest_buffer_ = buffer_idx; 135 } 136 new_frame_cond_var_.notify_all(); 137 } 138 139 vsoc::CuttlefishConfig* config_; 140 std::vector<std::uint8_t> buffer_ = 141 std::vector<std::uint8_t>(NUM_BUFFERS_ * ScreenSizeInBytes()); 142 std::uint32_t seq_num_{0}; 143 int newest_buffer_ = 0; 144 std::condition_variable new_frame_cond_var_; 145 std::mutex new_frame_mtx_; 146 std::thread screen_server_thread_; 147 }; 148 } // namespace 149 Get()150ScreenConnector* ScreenConnector::Get() { 151 auto config = vsoc::CuttlefishConfig::Get(); 152 if (config->enable_ivserver()) { 153 return new VSoCScreenConnector(); 154 } else { 155 return new SocketBasedScreenConnector(config); 156 } 157 } 158 159 } // namespace vnc 160 } // namespace cvd