1 /*
2 * Copyright (C) 2025 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/libs/vm_manager/crosvm_display_controller.h"
18
19 #include <android-base/logging.h>
20 #include <cstddef>
21 #include <iostream>
22 #include <string>
23 #include <vector>
24 #include "common/libs/utils/result.h"
25 #include "common/libs/utils/subprocess.h"
26 #include "host/libs/config/cuttlefish_config.h"
27
28 namespace cuttlefish {
29 namespace vm_manager {
30
GetCrosvmDisplayController()31 Result<CrosvmDisplayController> GetCrosvmDisplayController() {
32 auto config = CuttlefishConfig::Get();
33 if (!config) {
34 return CF_ERR("Failed to get Cuttlefish config.");
35 }
36 auto vm_manager = config->vm_manager();
37 if (vm_manager != VmmMode::kCrosvm) {
38 LOG(ERROR) << "Expected vm_manager is kCrosvm but " << vm_manager;
39 return CF_ERR(
40 "CrosvmDisplayController is only available when VmmMode is kCrosvm");
41 }
42 return CrosvmDisplayController(config);
43 }
44
Add(const int instance_num,const std::vector<CuttlefishConfig::DisplayConfig> & display_configs) const45 Result<int> CrosvmDisplayController::Add(
46 const int instance_num,
47 const std::vector<CuttlefishConfig::DisplayConfig>& display_configs) const {
48 std::vector<std::string> command_args;
49 command_args.push_back("add-displays");
50
51 for (const auto& display_config : display_configs) {
52 const std::string w = std::to_string(display_config.width);
53 const std::string h = std::to_string(display_config.height);
54 const std::string dpi = std::to_string(display_config.dpi);
55 const std::string rr = std::to_string(display_config.refresh_rate_hz);
56
57 const std::string add_display_flag =
58 "--gpu-display=" + android::base::Join(
59 std::vector<std::string>{
60 "mode=windowed[" + w + "," + h + "]",
61 "dpi=[" + dpi + "," + dpi + "]",
62 "refresh-rate=" + rr,
63 },
64 ",");
65
66 command_args.push_back(add_display_flag);
67 }
68
69 return RunCrosvmDisplayCommand(instance_num, command_args, NULL);
70 }
71
Remove(const int instance_num,const std::vector<std::string> display_ids) const72 Result<int> CrosvmDisplayController::Remove(
73 const int instance_num, const std::vector<std::string> display_ids) const {
74 std::vector<std::string> command_args;
75 command_args.push_back("remove-displays");
76
77 for (const auto& display_id : display_ids) {
78 command_args.push_back("--display-id=" + display_id);
79 }
80
81 return RunCrosvmDisplayCommand(instance_num, command_args, NULL);
82 }
83
List(const int instance_num)84 Result<std::string> CrosvmDisplayController::List(const int instance_num) {
85 std::string out;
86 CF_EXPECT(RunCrosvmDisplayCommand(instance_num, {"list-displays"}, &out));
87 return out;
88 }
89
RunCrosvmDisplayCommand(const int instance_num,const std::vector<std::string> & args,std::string * stdout_str) const90 Result<int> CrosvmDisplayController::RunCrosvmDisplayCommand(
91 const int instance_num, const std::vector<std::string>& args,
92 std::string* stdout_str) const {
93 // TODO(b/260649774): Consistent executable API for selecting an instance
94 const CuttlefishConfig::InstanceSpecific instance =
95 config_->ForInstance(instance_num);
96
97 const std::string crosvm_binary_path = instance.crosvm_binary();
98 const std::string crosvm_control_path = instance.CrosvmSocketPath();
99
100 Command command(crosvm_binary_path);
101 command.AddParameter("gpu");
102 for (const std::string& arg : args) {
103 command.AddParameter(arg);
104 }
105 command.AddParameter(crosvm_control_path);
106
107 std::string err;
108 auto ret = RunWithManagedStdio(std::move(command), NULL, stdout_str, &err);
109 if (ret != 0) {
110 LOG(ERROR) << "Failed to run crosvm display command: ret code: " << ret
111 << "\n"
112 << err << std::endl;
113 return CF_ERRF("Failed to run crosvm display command: ret code: {}", ret);
114 }
115
116 return 0;
117 }
118
119 } // namespace vm_manager
120 } // namespace cuttlefish
121