/* * Copyright (C) 2023 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. */ #include "host/libs/config/display.h" #include #include #include #include #include #include "common/libs/utils/contains.h" #include "common/libs/utils/flag_parser.h" #include "host/commands/assemble_cvd/flags_defaults.h" namespace cuttlefish { namespace { static constexpr char kDisplay0FlagName[] = "display0"; static constexpr char kDisplay1FlagName[] = "display1"; static constexpr char kDisplay2FlagName[] = "display2"; static constexpr char kDisplay3FlagName[] = "display3"; } // namespace Result> ParseDisplayConfig( const std::string& flag) { if (flag.empty()) { return std::nullopt; } std::unordered_map props; const std::vector pairs = android::base::Split(flag, ","); for (const std::string& pair : pairs) { const std::vector keyvalue = android::base::Split(pair, "="); CF_EXPECT_EQ(keyvalue.size(), 2, "Invalid display flag key-value: \"" << flag << "\""); const std::string& prop_key = keyvalue[0]; const std::string& prop_val = keyvalue[1]; props[prop_key] = prop_val; } CF_EXPECT(Contains(props, "width"), "Display configuration missing 'width' in \"" << flag << "\""); CF_EXPECT(Contains(props, "height"), "Display configuration missing 'height' in \"" << flag << "\""); int display_width; CF_EXPECT(android::base::ParseInt(props["width"], &display_width), "Display configuration invalid 'width' in \"" << flag << "\""); int display_height; CF_EXPECT(android::base::ParseInt(props["height"], &display_height), "Display configuration invalid 'height' in \"" << flag << "\""); int display_dpi = CF_DEFAULTS_DISPLAY_DPI; auto display_dpi_it = props.find("dpi"); if (display_dpi_it != props.end()) { CF_EXPECT(android::base::ParseInt(display_dpi_it->second, &display_dpi), "Display configuration invalid 'dpi' in \"" << flag << "\""); } int display_refresh_rate_hz = CF_DEFAULTS_DISPLAY_REFRESH_RATE; auto display_refresh_rate_hz_it = props.find("refresh_rate_hz"); if (display_refresh_rate_hz_it != props.end()) { CF_EXPECT(android::base::ParseInt(display_refresh_rate_hz_it->second, &display_refresh_rate_hz), "Display configuration invalid 'refresh_rate_hz' in \"" << flag << "\""); } return CuttlefishConfig::DisplayConfig{ .width = display_width, .height = display_height, .dpi = display_dpi, .refresh_rate_hz = display_refresh_rate_hz, }; } Result> ParseDisplayConfigsFromArgs(std::vector& args) { std::string display0_flag_value; std::string display1_flag_value; std::string display2_flag_value; std::string display3_flag_value; std::vector repeated_display_flag_values; const std::vector display_flags = { GflagsCompatFlag(kDisplay0FlagName, display0_flag_value) .Help(kDisplayHelp), GflagsCompatFlag(kDisplay1FlagName, display1_flag_value) .Help(kDisplayHelp), GflagsCompatFlag(kDisplay2FlagName, display2_flag_value) .Help(kDisplayHelp), GflagsCompatFlag(kDisplay3FlagName, display3_flag_value) .Help(kDisplayHelp), GflagsCompatFlag(kDisplayFlag) .Help(kDisplayHelp) .Setter([&](const FlagMatch& match) -> Result { repeated_display_flag_values.push_back(match.value); return {}; }), }; CF_EXPECT(ConsumeFlags(display_flags, args), "Failed to parse display flags."); std::vector displays_configs; auto display0 = CF_EXPECT(ParseDisplayConfig(display0_flag_value)); if (display0) { displays_configs.push_back(*display0); } auto display1 = CF_EXPECT(ParseDisplayConfig(display1_flag_value)); if (display1) { displays_configs.push_back(*display1); } auto display2 = CF_EXPECT(ParseDisplayConfig(display2_flag_value)); if (display2) { displays_configs.push_back(*display2); } auto display3 = CF_EXPECT(ParseDisplayConfig(display3_flag_value)); if (display3) { displays_configs.push_back(*display3); } for (const std::string& display_params : repeated_display_flag_values) { auto display = CF_EXPECT(ParseDisplayConfig(display_params)); if (display) { displays_configs.push_back(*display); } } return displays_configs; } } // namespace cuttlefish