X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=grpc-proxy%2Fmain-grpc.cpp;h=db3303270d0376051186924d204b23641dee2e3f;hb=ec6f2d31293d8680a1f6dab8f53949b848bbae08;hp=b2eca846c7bbd0700cb2705f4d1aeccbbc8696d4;hpb=ca537df2c52990acf97fb1c42ec2d993c60eae2d;p=src%2Fagl-compositor.git diff --git a/grpc-proxy/main-grpc.cpp b/grpc-proxy/main-grpc.cpp index b2eca84..db33032 100644 --- a/grpc-proxy/main-grpc.cpp +++ b/grpc-proxy/main-grpc.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "shell.h" @@ -36,38 +37,10 @@ #include "main-grpc.h" #include "grpc-async-cb.h" -struct shell_data_init { - struct agl_shell *shell; - bool wait_for_bound; - bool bound_ok; - bool bound_fail; - int version; -}; +using namespace std::chrono_literals; static int running = 1; -static void -agl_shell_bound_ok_init(void *data, struct agl_shell *agl_shell) -{ - (void) agl_shell; - - struct shell_data_init *sh = static_cast(data); - sh->wait_for_bound = false; - - sh->bound_ok = true; -} - -static void -agl_shell_bound_fail_init(void *data, struct agl_shell *agl_shell) -{ - (void) agl_shell; - - struct shell_data_init *sh = static_cast(data); - sh->wait_for_bound = false; - - sh->bound_fail = true; -} - static void agl_shell_bound_ok(void *data, struct agl_shell *agl_shell) { @@ -76,6 +49,7 @@ agl_shell_bound_ok(void *data, struct agl_shell *agl_shell) struct shell_data *sh = static_cast(data); sh->wait_for_bound = false; + LOG("bound_ok event!\n"); sh->bound_ok = true; } @@ -87,7 +61,9 @@ agl_shell_bound_fail(void *data, struct agl_shell *agl_shell) struct shell_data *sh = static_cast(data); sh->wait_for_bound = false; + LOG("bound_fail event!\n"); sh->bound_ok = false; + sh->bound_fail = true; } static void @@ -129,7 +105,7 @@ agl_shell_app_on_output(void *data, struct agl_shell *agl_shell, (void) data; (void) app_id; - LOG("got app_on_output event app_id %s on output\n", app_id, output_name); + LOG("got app_on_output event app_id %s on output %s\n", app_id, output_name); } @@ -140,13 +116,6 @@ static const struct agl_shell_listener shell_listener = { agl_shell_app_on_output, }; -static const struct agl_shell_listener shell_listener_init = { - agl_shell_bound_ok_init, - agl_shell_bound_fail_init, - nullptr, - nullptr, -}; - static void agl_shell_ext_doas_done(void *data, struct agl_shell_ext *agl_shell_ext, uint32_t status) { @@ -155,8 +124,10 @@ agl_shell_ext_doas_done(void *data, struct agl_shell_ext *agl_shell_ext, uint32_ struct shell_data *sh = static_cast(data); sh->wait_for_doas = false; - if (status == AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS) + if (status == AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS) { + LOG("got doas_ok true!\n"); sh->doas_ok = true; + } } static const struct agl_shell_ext_listener shell_ext_listener = { @@ -270,249 +241,133 @@ global_add(void *data, struct wl_registry *reg, uint32_t id, if (!sh) return; - if (strcmp(interface, agl_shell_interface.name) == 0) { - // bind to at least v3 to get events - sh->shell = - static_cast(wl_registry_bind(reg, id, - &agl_shell_interface, - std::min(static_cast(10), version))); - agl_shell_add_listener(sh->shell, &shell_listener, data); - sh->version = version; - } else if (strcmp(interface, "wl_output") == 0) { - display_add_output(sh, reg, id, version); - } -} - -// the purpose of this _init is to make sure we're not the first shell client -// running to allow the 'main' shell client take over. -static void -global_add_init(void *data, struct wl_registry *reg, uint32_t id, - const char *interface, uint32_t version) -{ - - struct shell_data_init *sh = static_cast(data); + struct global_data gb; - if (!sh) - return; + gb.version = version; + gb.id = id; + gb.interface_name = std::string(interface); + sh->globals.push_back(gb); if (strcmp(interface, agl_shell_interface.name) == 0) { - sh->shell = - static_cast(wl_registry_bind(reg, id, - &agl_shell_interface, - std::min(static_cast(10), version))); - agl_shell_add_listener(sh->shell, &shell_listener_init, data); - sh->version = version; + // nothing here, we're just going to bind a bit later after we + // got doas_ok event + } else if (strcmp(interface, "wl_output") == 0) { + display_add_output(sh, reg, id, version); + } else if (strcmp(interface, agl_shell_ext_interface.name) == 0) { + sh->shell_ext = + static_cast(wl_registry_bind(reg, id, + &agl_shell_ext_interface, + std::min(static_cast(1), version))); + agl_shell_ext_add_listener(sh->shell_ext, + &shell_ext_listener, data); } } static void global_remove(void *data, struct wl_registry *reg, uint32_t id) { + struct shell_data *sh = static_cast(data); /* Don't care */ - (void) data; (void) reg; (void) id; -} -static void -global_add_ext(void *data, struct wl_registry *reg, uint32_t id, - const char *interface, uint32_t version) -{ - struct shell_data *sh = static_cast(data); - - if (!sh) - return; - - if (strcmp(interface, agl_shell_ext_interface.name) == 0) { - sh->shell_ext = - static_cast(wl_registry_bind(reg, id, - &agl_shell_ext_interface, - std::min(static_cast(1), version))); - agl_shell_ext_add_listener(sh->shell_ext, - &shell_ext_listener, data); - } + for (std::list::iterator it = sh->globals.begin(); + it != sh->globals.end(); it = sh->globals.erase(it)) + ; } -static const struct wl_registry_listener registry_ext_listener = { - global_add_ext, - global_remove, -}; - static const struct wl_registry_listener registry_listener = { global_add, global_remove, }; -static const struct wl_registry_listener registry_listener_init = { - global_add_init, - global_remove, -}; - -static void -register_shell_ext(struct wl_display *wl_display, struct shell_data *sh) -{ - struct wl_registry *registry; - registry = wl_display_get_registry(wl_display); - - wl_registry_add_listener(registry, ®istry_ext_listener, sh); - - wl_display_roundtrip(wl_display); - wl_registry_destroy(registry); -} - -static void -register_shell(struct wl_display *wl_display, struct shell_data *sh) -{ - struct wl_registry *registry; - - wl_list_init(&sh->output_list); - - registry = wl_display_get_registry(wl_display); - - wl_registry_add_listener(registry, ®istry_listener, sh); - - wl_display_roundtrip(wl_display); - wl_registry_destroy(registry); -} - -static int -__register_shell_init(void) +// we expect this client to be up & running *after* the shell client has +// already set-up panels/backgrounds. +// +// this means we need to wait for doas_done event with doas_shell_client_status +// set to sucess. +struct shell_data * +register_shell_ext(void) { + // try first to bind to agl_shell_ext int ret = 0; struct wl_registry *registry; - struct wl_display *wl_display; - - struct shell_data_init *sh = new struct shell_data_init; - - wl_display = wl_display_connect(NULL); - registry = wl_display_get_registry(wl_display); - sh->wait_for_bound = true; - sh->bound_fail = false; - sh->bound_ok = false; - wl_registry_add_listener(registry, ®istry_listener_init, sh); - wl_display_roundtrip(wl_display); + struct shell_data *sh = new struct shell_data; - if (!sh->shell || sh->version < 3) { - ret = -1; + sh->wl_display = wl_display_connect(NULL); + if (!sh->wl_display) { goto err; } - while (ret !=- 1 && sh->wait_for_bound) { - ret = wl_display_dispatch(wl_display); + registry = wl_display_get_registry(sh->wl_display); - if (sh->wait_for_bound) - continue; - } + sh->wait_for_bound = true; + sh->wait_for_doas = true; - ret = sh->bound_fail; + sh->bound_fail = false; + sh->bound_ok = false; - agl_shell_destroy(sh->shell); - wl_display_flush(wl_display); -err: - wl_registry_destroy(registry); - wl_display_disconnect(wl_display); - delete sh; - return ret; -} + sh->doas_ok = false; + wl_list_init(&sh->output_list); -// we expect this client to be up & running *after* the shell client has -// already set-up panels/backgrounds. -// this means the very first try to bind to agl_shell we wait for -// 'bound_fail' event, which would tell us when it's ok to attempt to -// bind agl_shell_ext, call doas request, then attempt to bind (one -// more time) to agl_shell but this time wait for 'bound_ok' event. -void -register_shell_init(void) -{ - struct timespec ts = {}; + wl_registry_add_listener(registry, ®istry_listener, sh); + wl_display_roundtrip(sh->wl_display); - clock_gettime(CLOCK_MONOTONIC, &ts); + if (!sh->shell_ext) { + LOG("agl_shell_ext interface was not found!\n"); + goto err; + } - ts.tv_sec = 0; - ts.tv_nsec = 250 * 1000 * 1000; // 250 ms + do { + // this should loop until we get back an doas_ok event + agl_shell_ext_doas_shell_client(sh->shell_ext); - // verify if 'bound_fail' was received - while (true) { + while (ret !=- 1 && sh->wait_for_doas) { + ret = wl_display_dispatch(sh->wl_display); - int r = __register_shell_init(); + if (sh->wait_for_doas) + continue; + } - if (r < 0) { - LOG("agl-shell extension not found or version too low\n"); - exit(EXIT_FAILURE); - } else if (r == 1) { - // we need to get a 'bound_fail' event, if we get a 'bound_ok' - // it means we're the first shell to start so wait until the - // shell client actually started - LOG("Found another shell client running. " - "Going further to bind to the agl_shell_ext interface\n"); + if (sh->doas_ok) { break; } - LOG("No shell client detected running. Will wait until one starts up...\n"); - nanosleep(&ts, NULL); - } - -} - -static void -destroy_shell_data(struct shell_data *sh) -{ - struct window_output *w_output, *w_output_next; - - wl_list_for_each_safe(w_output, w_output_next, &sh->output_list, link) - destroy_output(w_output); - - wl_display_flush(sh->wl_display); - wl_display_disconnect(sh->wl_display); - - delete sh; -} - -static struct shell_data * -start_agl_shell_client(void) -{ - int ret = 0; - struct wl_display *wl_display; - - wl_display = wl_display_connect(NULL); - - struct shell_data *sh = new struct shell_data; - - sh->wl_display = wl_display; - sh->wait_for_doas = true; - sh->wait_for_bound = true; + std::this_thread::sleep_for(250ms); + sh->wait_for_doas = true; + } while (!sh->doas_ok); - register_shell_ext(wl_display, sh); - - // check for agl_shell_ext - if (!sh->shell_ext) { - LOG("Failed to bind to agl_shell_ext interface\n"); + if (!sh->doas_ok) { + LOG("agl_shell_ext: failed to get doas_ok status\n"); goto err; } - if (wl_list_empty(&sh->output_list)) { - LOG("Failed get any outputs!\n"); - goto err; - } - agl_shell_ext_doas_shell_client(sh->shell_ext); - while (ret != -1 && sh->wait_for_doas) { - ret = wl_display_dispatch(sh->wl_display); - if (sh->wait_for_doas) - continue; + // search for the globals to get id and version + for (std::list::iterator it = sh->globals.begin(); + it != sh->globals.end(); it++) { + if (it->interface_name == "agl_shell") { + sh->shell = + static_cast(wl_registry_bind(registry, it->id, + &agl_shell_interface, std::min(static_cast(11), + it->version)) + ); + agl_shell_add_listener(sh->shell, &shell_listener, sh); + break; + } } - if (!sh->doas_ok) { - LOG("Failed to get doas_done event\n"); + if (!sh->shell) { + LOG("agl_shell was not advertised!\n"); goto err; } - // bind to agl-shell - register_shell(wl_display, sh); + // wait to bound now while (ret != -1 && sh->wait_for_bound) { ret = wl_display_dispatch(sh->wl_display); + if (sh->wait_for_bound) continue; } @@ -523,31 +378,35 @@ start_agl_shell_client(void) goto err; } - LOG("agl_shell/agl_shell_ext interface OK\n"); - + LOG("agl_shell/agl_shell_ext interfaces OK\n"); return sh; err: - delete sh; - return nullptr; + LOG("agl_shell/agl_shell_ext interfaces NOK\n"); + return NULL; } static void -start_grpc_server(Shell *aglShell) +destroy_shell_data(struct shell_data *sh) { - // instantiante the grpc server - std::string server_address(kDefaultGrpcServiceAddress); - GrpcServiceImpl service{aglShell}; + struct window_output *w_output, *w_output_next; - grpc::EnableDefaultHealthCheckService(true); - grpc::reflection::InitProtoReflectionServerBuilderPlugin(); + wl_list_for_each_safe(w_output, w_output_next, &sh->output_list, link) + destroy_output(w_output); - grpc::ServerBuilder builder; - builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); - builder.RegisterService(&service); + for (std::list::iterator it = sh->globals.begin(); + it != sh->globals.end(); it = sh->globals.erase(it)) + ; - std::unique_ptr server(builder.BuildAndStart()); - LOG("gRPC server listening on %s\n", server_address.c_str()); + wl_display_flush(sh->wl_display); + wl_display_disconnect(sh->wl_display); + delete sh; +} + +static void +start_grpc_server(std::shared_ptr server) +{ + LOG("gRPC server listening\n"); server->Wait(); } @@ -555,29 +414,44 @@ int main(int argc, char **argv) { (void) argc; (void) argv; - Shell *aglShell; + Shell *aglShell = nullptr; int ret = 0; + // instantiante the grpc server + std::string server_address(kDefaultGrpcServiceAddress); + GrpcServiceImpl service{aglShell}; + + grpc::EnableDefaultHealthCheckService(true); + grpc::reflection::InitProtoReflectionServerBuilderPlugin(); + + grpc::ServerBuilder builder; + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + + std::shared_ptr server(builder.BuildAndStart()); + std::thread thread(start_grpc_server, server); + // this blocks until we detect that another shell client started // running - register_shell_init(); - - struct shell_data *sh = start_agl_shell_client(); + struct shell_data *sh = register_shell_ext(); if (!sh) { - LOG("Failed to initialize agl-shell/agl-shell-ext\n"); + LOG("Failed to get register ag_shell_ext\n"); + thread.join(); exit(EXIT_FAILURE); } std::shared_ptr agl_shell{sh->shell, agl_shell_destroy}; aglShell = new Shell(agl_shell, sh); - std::thread thread(start_grpc_server, aglShell); + // now that we have aglShell, set it to the gRPC proxy as well + service.setAglShell(aglShell); // serve wayland requests while (running && ret != -1) { ret = wl_display_dispatch(sh->wl_display); } + thread.join(); destroy_shell_data(sh); return 0; }