Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit

Permalink
vm_tools: sommelier: Load quirks config files specified on command line.
Browse files Browse the repository at this point in the history
BUG=b:296327135
TEST=run unit tests: meson setup builddir -Dquirks=true; pushd builddir; ninja && ./sommelier_test; popd

Change-Id: I5543dd9d5871b7155f45535776f4e012b45c3bf8
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/4903448
Commit-Queue: Chloe Pelling <[email protected]>
Reviewed-by: Nic Hollingum <[email protected]>
Tested-by: Chloe Pelling <[email protected]>
  • Loading branch information
cpelling authored and Chromeos LUCI committed Oct 10, 2023
1 parent ecaeb62 commit 2600078
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 18 deletions.
66 changes: 48 additions & 18 deletions quirks/sommelier-quirks-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <cstdio>
#include <fstream>
#include <gtest/gtest.h>
#include <set>
#include <string>
#include <sstream>
#include <unistd.h>

#include "quirks/quirks.pb.h"
#include "sommelier-quirks.h" // NOLINT(build/include_directory)
Expand All @@ -15,80 +17,108 @@ namespace vm_tools::sommelier {

using QuirksTest = X11TestBase;

TEST_F(QuirksTest, LoadsFilesFromCommandLine) {
sl_window* game123 = CreateToplevelWindow();
game123->steam_game_id = 123;
sl_window* game456 = CreateToplevelWindow();
game456->steam_game_id = 456;
char filename1[L_tmpnam];
char filename2[L_tmpnam];
{
std::ofstream file1(std::tmpnam(filename1), std::ofstream::out);
file1 << "sommelier { \n"
" condition { steam_game_id: 123 }\n"
" enable: FEATURE_X11_MOVE_WINDOWS\n"
"}";
}
{
std::ofstream file2(std::tmpnam(filename2), std::ofstream::out);
file2 << "sommelier { \n"
" condition { steam_game_id: 456 }\n"
" enable: FEATURE_X11_MOVE_WINDOWS\n"
"}";
}

std::stringstream paths;
paths << filename1 << "," << filename2;
ctx.quirks.LoadFromCommaSeparatedFiles(paths.str().c_str());

EXPECT_TRUE(ctx.quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_TRUE(ctx.quirks.IsEnabled(game456, quirks::FEATURE_X11_MOVE_WINDOWS));
unlink(filename1);
unlink(filename2);
}

TEST_F(QuirksTest, ShouldSelectivelyEnableFeatures) {
sl_window* game123 = CreateToplevelWindow();
game123->steam_game_id = 123;
sl_window* game456 = CreateToplevelWindow();
game456->steam_game_id = 456;
Quirks quirks;

quirks.Load(
ctx.quirks.Load(
"sommelier { \n"
" condition { steam_game_id: 123 }\n"
" enable: FEATURE_X11_MOVE_WINDOWS\n"
"}");

EXPECT_TRUE(quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_FALSE(quirks.IsEnabled(game456, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_TRUE(ctx.quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_FALSE(ctx.quirks.IsEnabled(game456, quirks::FEATURE_X11_MOVE_WINDOWS));
}

TEST_F(QuirksTest, LaterRulesTakePriority) {
sl_window* game123 = CreateToplevelWindow();
game123->steam_game_id = 123;
Quirks quirks;

// Act: Load conflicting rules.
quirks.Load(
ctx.quirks.Load(
"sommelier { \n"
" condition { steam_game_id: 123 }\n"
" enable: FEATURE_X11_MOVE_WINDOWS\n"
"}");
quirks.Load(
ctx.quirks.Load(
"sommelier { \n"
" condition { steam_game_id: 123 }\n"
" disable: FEATURE_X11_MOVE_WINDOWS\n"
"}");

// Assert: Feature is disabled, since that rule was last.
EXPECT_FALSE(quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_FALSE(ctx.quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));

// Act: Load another rule that enables the feature.
quirks.Load(
ctx.quirks.Load(
"sommelier { \n"
" condition { steam_game_id: 123 }\n"
" enable: FEATURE_X11_MOVE_WINDOWS\n"
"}");

// Assert: Feature is now enabled.
EXPECT_TRUE(quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_TRUE(ctx.quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
}

TEST_F(QuirksTest, EmptyConditionsAreFalse) {
sl_window* window = CreateToplevelWindow();
Quirks quirks;

quirks.Load(
ctx.quirks.Load(
"sommelier { \n"
" condition { }\n"
" enable: FEATURE_X11_MOVE_WINDOWS\n"
"}");

EXPECT_FALSE(quirks.IsEnabled(window, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_FALSE(ctx.quirks.IsEnabled(window, quirks::FEATURE_X11_MOVE_WINDOWS));
}

TEST_F(QuirksTest, AllConditionsMustMatch) {
sl_window* game123 = CreateToplevelWindow();
game123->steam_game_id = 123;
Quirks quirks;

quirks.Load(
ctx.quirks.Load(
"sommelier { \n"
" condition { steam_game_id: 123 }\n"
" condition { steam_game_id: 456 }\n"
" enable: FEATURE_X11_MOVE_WINDOWS\n"
"}");

EXPECT_FALSE(quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
EXPECT_FALSE(ctx.quirks.IsEnabled(game123, quirks::FEATURE_X11_MOVE_WINDOWS));
}

} // namespace vm_tools::sommelier
33 changes: 33 additions & 0 deletions quirks/sommelier-quirks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,50 @@
// found in the LICENSE file.

#include "builddir/libsommelier.a.p/quirks/quirks.pb.h"
#include <fcntl.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include "quirks/quirks.pb.h"
#include "quirks/sommelier-quirks.h"
#include <set>
#include "sommelier-window.h" // NOLINT(build/include_directory)
#include <string.h>
#include <unistd.h>

void Quirks::Load(std::string textproto) {
google::protobuf::TextFormat::MergeFromString(textproto, &active_config_);
Update();
}

void Quirks::LoadFromCommaSeparatedFiles(const char* paths) {
const char* start = paths;
const char* end;
do {
// Find the next comma (or end of string).
end = strchrnul(start, ',');
// `start` and `end` delimit a path; load rules from it.
std::string path(start, end - start);
LoadFromFile(path);
// The next string starts after the comma
start = end + 1;
// Terminate on null char.
} while (*end != '\0');
}

void Quirks::LoadFromFile(std::string path) {
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0) {
const char* e = strerror(errno);
fprintf(stderr, "Failed to open quirks config: %s: %s\n", path.c_str(), e);
return;
}
google::protobuf::io::FileInputStream f(fd);
if (google::protobuf::TextFormat::Merge(&f, &active_config_)) {
Update();
}
close(fd);
}

bool Quirks::IsEnabled(struct sl_window* window, int feature) {
return enabled_features_.find(std::make_pair(
window->steam_game_id, feature)) != enabled_features_.end();
Expand Down
6 changes: 6 additions & 0 deletions quirks/sommelier-quirks.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ class Quirks {
// Parse `textproto` as a Config proto, and merge it into the active config.
void Load(std::string textproto);

// Call `LoadFromFile` for each filename separated by commas in `paths`.
void LoadFromCommaSeparatedFiles(const char* paths);

// Load a Config textproto from `path`, and merge it into the active config.
void LoadFromFile(std::string path);

// Whether the given Feature (from quirks.proto) is enabled for the given
// `window`, according to the active config.
bool IsEnabled(struct sl_window* window, int feature);
Expand Down
3 changes: 3 additions & 0 deletions sommelier-ctx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ void sl_context_init_default(struct sl_context* ctx) {
}
ctx->timing = nullptr;
ctx->trace_filename = nullptr;
#ifdef QUIRKS_SUPPORT
new (&ctx->quirks) Quirks();
#endif
ctx->enable_xshape = false;
ctx->enable_x11_move_windows = false;
ctx->trace_system = false;
Expand Down
7 changes: 7 additions & 0 deletions sommelier-ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#include "sommelier-util.h" // NOLINT(build/include_directory)
#include "virtualization/wayland_channel.h"

#ifdef QUIRKS_SUPPORT
#include "quirks/sommelier-quirks.h"
#endif

#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

Expand Down Expand Up @@ -196,6 +200,9 @@ struct sl_context {
xcb_colormap_t colormaps[256];
Timing* timing;
const char* trace_filename;
#ifdef QUIRKS_SUPPORT
Quirks quirks;
#endif

// Command-line configurable options.
bool trace_system;
Expand Down
16 changes: 16 additions & 0 deletions sommelier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3454,6 +3454,9 @@ static void sl_print_usage() {
#ifdef PERFETTO_TRACING
" --trace-filename=PATH\t\tPath to Perfetto trace filename\n"
" --trace-system\t\tPerfetto trace to system daemon\n"
#endif
#ifdef QUIRKS_SUPPORT
" --quirks-config=PATH[,PATH...]\tOne or more 'quirks' config files.\n"
#endif
" --fullscreen-mode=MODE\tDefault fullscreen behavior (immersive,"
" plain)\n"
Expand Down Expand Up @@ -3816,6 +3819,9 @@ int real_main(int argc, char** argv) {
const char* xauth_path = getenv("SOMMELIER_XAUTH_PATH");
const char* xfont_path = getenv("SOMMELIER_XFONT_PATH");
const char* vm_id = getenv("SOMMELIER_VM_IDENTIFIER");
#ifdef QUIRKS_SUPPORT
const char* quirks_paths = getenv("SOMMELIER_QUIRKS_CONFIG");
#endif
const char* socket_name = "wayland-0";
bool noop_driver = false;
struct wl_event_loop* event_loop;
Expand Down Expand Up @@ -3924,6 +3930,10 @@ int real_main(int argc, char** argv) {
ctx.trace_filename = sl_arg_value(arg);
} else if (strstr(arg, "--trace-system") == arg) {
ctx.trace_system = true;
#endif
#ifdef QUIRKS_SUPPORT
} else if (strstr(arg, "--quirks-config") == arg) {
quirks_paths = sl_arg_value(arg);
#endif
} else if (arg[0] == '-') {
if (strcmp(arg, "--") == 0) {
Expand Down Expand Up @@ -4008,6 +4018,12 @@ int real_main(int argc, char** argv) {
ctx.support_damage_buffer = support_damage_buffer == nullptr ||
strcmp(support_damage_buffer, "1") == 0;

#ifdef QUIRKS_SUPPORT
if (quirks_paths) {
ctx.quirks.LoadFromCommaSeparatedFiles(quirks_paths);
}
#endif

if (fullscreen_mode) {
if (strcmp(fullscreen_mode, "immersive") == 0) {
ctx.fullscreen_mode = ZAURA_SURFACE_FULLSCREEN_MODE_IMMERSIVE;
Expand Down

0 comments on commit 2600078

Please sign in to comment.