• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()150 ScreenConnector* 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