From b4f8b826847488ba8745e5c0161df6ef16fd4583 Mon Sep 17 00:00:00 2001 From: Elvis Capia <116971915+elviscapiaq@users.noreply.github.com> Date: Thu, 30 Jan 2025 11:19:28 -0500 Subject: [PATCH] Running gRPC Server independently (#158) The loading/unloading behavior of the Vulkan/OpenXR Dive layer library varies significantly across Android applications. For example for Vulkan apps it loads - unloads - reloads the library during execution. For an Unity-based OpenXR app that creates two instances, the behavior is the same. The gRPC Server starts when the library loads for the first time. Then, a function prevents the library from being unloaded. This keeps both the library and server loaded exactly once, even if apps try to reload or close them. In this way, the Server lives for the entire lifecycle of the app. --- capture_service/server.cc | 5 ++-- capture_service/server.h | 5 ++-- capture_service/service.cc | 23 ++++++++++++++++-- layer/layer_common.cc | 48 ++++++++++++++++++++++++++++++++++++-- layer/openxr_layer.cc | 9 +------ layer/vk_layer_base.cc | 6 ----- 6 files changed, 74 insertions(+), 22 deletions(-) diff --git a/capture_service/server.cc b/capture_service/server.cc index aebf6016e..8c5ab528e 100644 --- a/capture_service/server.cc +++ b/capture_service/server.cc @@ -16,7 +16,8 @@ limitations under the License. #include "server.h" -int main(int argc, char **argv) { - Dive::server_main(); +int main(int argc, char **argv) +{ + Dive::ServerMain(); return 0; } diff --git a/capture_service/server.h b/capture_service/server.h index 8e983b64b..98eba2379 100644 --- a/capture_service/server.h +++ b/capture_service/server.h @@ -18,5 +18,6 @@ limitations under the License. namespace Dive { -int server_main(); -} +int ServerMain(); +void StopServer(); +} // namespace Dive diff --git a/capture_service/service.cc b/capture_service/service.cc index 3f3ab0b00..193b666f9 100644 --- a/capture_service/service.cc +++ b/capture_service/service.cc @@ -132,8 +132,26 @@ grpc::Status DiveServiceImpl::DownloadFile(grpc::ServerContext *cont return grpc::Status::OK; } +std::unique_ptr &GetServer() +{ + static std::unique_ptr server = nullptr; + return server; +} + +void StopServer() +{ + auto &server = GetServer(); + if (server) + { + LOGI("StopServer at service.cc"); + server->Shutdown(); + server = nullptr; + } +} + void RunServer(uint16_t port) { + LOGI("port is %d\n", port); std::string server_address = absl::StrFormat("0.0.0.0:%d", port); DiveServiceImpl service; @@ -142,12 +160,13 @@ void RunServer(uint16_t port) builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); - std::unique_ptr server(builder.BuildAndStart()); + auto &server = GetServer(); + server = builder.BuildAndStart(); LOGI("Server listening on %s", server_address.c_str()); server->Wait(); } -int server_main() +int ServerMain() { RunServer(absl::GetFlag(FLAGS_port)); return 0; diff --git a/layer/layer_common.cc b/layer/layer_common.cc index 22e3344a2..ff36bc8f4 100644 --- a/layer/layer_common.cc +++ b/layer/layer_common.cc @@ -14,6 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ +#ifdef _WIN32 +# include +#else +# include +#endif + #include "layer_common.h" #include @@ -58,7 +64,7 @@ ServerRunner::ServerRunner() LOGI("libwrap loaded: %d", is_libwrap_loaded); if (is_libwrap_loaded) { - server_thread = std::thread(Dive::server_main); + server_thread = std::thread(Dive::ServerMain); } } @@ -66,6 +72,7 @@ ServerRunner::~ServerRunner() { if (is_libwrap_loaded && server_thread.joinable()) { + Dive::StopServer(); LOGI("Wait for server thread to join"); server_thread.join(); } @@ -77,4 +84,41 @@ ServerRunner &GetServerRunner() return runner; } -} // namespace DiveLayer \ No newline at end of file +} // namespace DiveLayer + +void PreventLibraryUnload() +{ +#ifdef _WIN32 + HMODULE module = nullptr; + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, + reinterpret_cast(&PreventLibraryUnload), + &module); +#else + Dl_info info; + if (dladdr(reinterpret_cast(&PreventLibraryUnload), &info)) + { + dlopen(info.dli_fname, RTLD_NOW | RTLD_NOLOAD | RTLD_LOCAL | RTLD_NODELETE); + } +#endif +} + +#ifdef _WIN32 +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + [[maybe_unused]] auto &server = DiveLayer::GetServerRunner(); + PreventLibraryUnload(); + } + return TRUE; +} +#else +extern "C" +{ + __attribute__((constructor)) void InitializeLibrary() + { + [[maybe_unused]] auto &server = DiveLayer::GetServerRunner(); + PreventLibraryUnload(); + } +} +#endif \ No newline at end of file diff --git a/layer/openxr_layer.cc b/layer/openxr_layer.cc index 2ad7355d5..8f4dd2308 100644 --- a/layer/openxr_layer.cc +++ b/layer/openxr_layer.cc @@ -56,12 +56,6 @@ struct XrSessionData { XrSession session; XrGeneratedDispatchTable dispatch_table; - ServerRunner &server; - - XrSessionData() : - server(GetServerRunner()) - { - } }; static thread_local XrInstanceData *last_used_xr_instance_data = nullptr; @@ -190,8 +184,7 @@ XRAPI_ATTR XrResult XRAPI_CALL ApiDiveLayerXrDestroyInstance(XrInstance instance LOGD("ApiDiveLayerXrDestroyInstance\n"); XrResult result = XR_SUCCESS; - - auto sess_data = GetXrInstanceLayerData(DataKey(instance)); + auto sess_data = GetXrInstanceLayerData(DataKey(instance)); if (sess_data) { result = sess_data->dispatch_table.DestroyInstance(instance); diff --git a/layer/vk_layer_base.cc b/layer/vk_layer_base.cc index 878cf61dc..a669b6306 100644 --- a/layer/vk_layer_base.cc +++ b/layer/vk_layer_base.cc @@ -43,12 +43,6 @@ struct InstanceData { VkInstance instance; InstanceDispatchTable dispatch_table; - ServerRunner &server; - - InstanceData() : - server(GetServerRunner()) - { - } }; struct DeviceData