diff --git a/libfprint/drivers/secugen.c b/libfprint/drivers/secugen.c index a2a3965f..a19b6c4f 100644 --- a/libfprint/drivers/secugen.c +++ b/libfprint/drivers/secugen.c @@ -2217,7 +2217,7 @@ dev_change_state (FpImageDevice *dev, case FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON: fp_dbg ("Awaiting finger (image-based detection)"); - /* Under FP_DEVICE_EMULATION (set by the umockdev test harness so + /* Under fpi_device_emulation (set by the umockdev test harness so * drivers can adapt to replay; see tests/meson.build) skip the * timer-driven detect poll: each poll consumes a full ~658KB frame, * so exercising it in replay would require recording an unbounded diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index 4063f91a..817c2a0f 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -22,10 +22,12 @@ #include #include #include +#include #include "fpi-log.h" #include "fp-device-private.h" +#include "tests/fpi-test-emulation.h" /** * SECTION: fpi-device @@ -50,19 +52,58 @@ fp_device_get_instance_private (FpDevice *self) g_type_class_get_instance_private_offset (dev_class)); } +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GModule, g_module_close) + /** * fpi_device_emulation_mode_enabled: * @device: The #FpDevice to check * * Checks if the device is running in emulation mode, which is enabled by * setting the FP_DEVICE_EMULATION environment variable to a '1' value but - * only when the test emulation library is pre-loaded. + * only when the test emulation library is loaded. * This is used by some drivers to enable special behavior for testing * and development purposes. */ -__attribute__((weak)) gboolean +gboolean (fpi_device_emulation_mode_enabled) (FpDevice *device) { + static gboolean (*real_fn)(FpDevice *) = NULL; + static gsize emulation_mode = 0; + + if (g_once_init_enter (&emulation_mode)) + { + if (g_strcmp0 (g_getenv (FPI_EMULATION_ENV_VAR), "1") == 0) + { + const char *dirs[] = { + FPI_EMULATION_HELPER_BUILDDIR, + FPI_EMULATION_HELPER_INSTALLDIR, + }; + + for (size_t i = 0; i < G_N_ELEMENTS (dirs); ++i) + { + g_autofree char *path = NULL; + g_autoptr(GModule) mod = NULL; + gpointer sym; + + path = g_build_filename (dirs[i], FPI_EMULATION_HELPER_MODULE, NULL); + if (!(mod = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL))) + continue; + + if (!g_module_symbol (mod, "fpi_device_emulation_mode_enabled", &sym)) + continue; + + real_fn = (gboolean (*)(FpDevice *)) sym; + g_steal_pointer (&mod); + break; + } + } + + g_once_init_leave (&emulation_mode, real_fn ? TRUE : G_MAXSIZE); + } + + if (real_fn) + return real_fn (device); + return FALSE; } diff --git a/libfprint/libfprint.ver b/libfprint/libfprint.ver index f754a6d4..d99a456a 100644 --- a/libfprint/libfprint.ver +++ b/libfprint/libfprint.ver @@ -1,7 +1,6 @@ LIBFPRINT_2.0.0 { global: fp_*; - fpi_device_emulation_mode_enabled; local: *; }; diff --git a/libfprint/meson.build b/libfprint/meson.build index 99865226..352a3759 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -210,6 +210,7 @@ deps = [ enums_dep, gio_dep, glib_dep, + gmodule_dep, gobject_dep, gusb_dep, mathlib_dep, diff --git a/meson.build b/meson.build index e7f1270a..538415ad 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,7 @@ versioned_libname = meson.project_name() + '-' + soversion.to_string() glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version) gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version) gobject_dep = dependency('gobject-2.0', version: '>=' + glib_min_version) +gmodule_dep = dependency('gmodule-2.0', version: '>=' + glib_min_version) gusb_dep = dependency('gusb', version: '>= 0.2.0') mathlib_dep = cc.find_library('m', required: false) diff --git a/tests/meson.build b/tests/meson.build index 2c1945a9..9b50b5a3 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -80,11 +80,18 @@ test_emulation_lib = shared_library('fprint-test-emulation', install: installed_tests, install_dir: installed_tests_execdir, ) -test_emulation_lib_name = fs.name(test_emulation_lib.full_path()) -# Preload the test-emulation library so that the weak NULL implementation -# in libfprint is overridden with one that honours FP_DEVICE_EMULATION. -envs.prepend('LD_PRELOAD', test_emulation_lib.full_path()) +# Paths where the test-emulation helper may be loaded via dlopen +test_emulation = configuration_data() +test_emulation.set_quoted('FPI_EMULATION_ENV_VAR', + 'FP_DEVICE_EMULATION') +test_emulation.set_quoted('FPI_EMULATION_HELPER_BUILDDIR', + meson.project_build_root() / 'tests') +test_emulation.set_quoted('FPI_EMULATION_HELPER_INSTALLDIR', + libexecdir / 'installed-tests' / versioned_libname) +test_emulation.set_quoted('FPI_EMULATION_HELPER_MODULE', + fs.name(test_emulation_lib.full_path())) +configure_file(output: 'fpi-test-emulation.h', configuration: test_emulation) env_parser_cmd = ''' import os; @@ -98,7 +105,6 @@ envs_str = run_command(python3, '-c', env_parser_cmd, envs_str = ' '.join([ envs_str, - 'LD_PRELOAD=' + (installed_tests_execdir / test_emulation_lib_name), 'G_TEST_SRCDIR=' + installed_tests_testdir, 'G_TEST_BUILDDIR=' + installed_tests_execdir, ]) @@ -225,7 +231,6 @@ if get_option('introspection') 'driver_test': driver_test, 'driver_env': ' '.join([ driver_envs_str, - 'LD_PRELOAD=' + (installed_tests_execdir / test_emulation_lib_name), 'LD_LIBRARY_PATH=' + installed_tests_libdir, # FIXME: Adding this requires gnome-desktop-testing!12 # 'GI_TYPELIB_PATH=' + installed_tests_libdir / 'girepository-1.0', diff --git a/tests/test-emulation.c b/tests/test-emulation.c index a204cc4a..c71c3662 100644 --- a/tests/test-emulation.c +++ b/tests/test-emulation.c @@ -17,6 +17,7 @@ */ #include "fpi-device.h" +#include "fpi-test-emulation.h" gboolean (fpi_device_emulation_mode_enabled) (FpDevice *device) @@ -25,7 +26,7 @@ gboolean if (g_once_init_enter (&emulation_mode)) g_once_init_leave (&emulation_mode, - g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0 ? + g_strcmp0 (g_getenv (FPI_EMULATION_ENV_VAR), "1") == 0 ? TRUE : G_MAXSIZE); return emulation_mode == TRUE;