GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 94.0% 875 / 0 / 931
Functions: 98.4% 60 / 0 / 61
Branches: 74.6% 422 / 0 / 566

libfprint/fpi-device.c
Line Branch Exec Source
1 /*
2 * FpDevice - A fingerprint reader device - Private APIs
3 * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
4 * Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "device"
22 #include <math.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <gmodule.h>
26
27 #include "fpi-log.h"
28
29 #include "fp-device-private.h"
30 #include "tests/fpi-test-emulation.h"
31
32 /**
33 * SECTION: fpi-device
34 * @title: Internal FpDevice
35 * @short_description: Internal device routines
36 *
37 * The methods that are available for drivers to manipulate a device. See
38 * #FpDeviceClass for more information. Also note that most of these are
39 * not relevant for image based devices, see #FpImageDeviceClass in that
40 * case.
41 *
42 * Also see the public #FpDevice routines.
43 */
44
45 /* Manually redefine what G_DEFINE_* macro does */
46 static inline gpointer
47 824437 fp_device_get_instance_private (FpDevice *self)
48 {
49 824437 FpDeviceClass *dev_class = g_type_class_peek_static (FP_TYPE_DEVICE);
50
51 824437 return G_STRUCT_MEMBER_P (self,
52 g_type_class_get_instance_private_offset (dev_class));
53 }
54
55 20 G_DEFINE_AUTOPTR_CLEANUP_FUNC (GModule, g_module_close)
56
57 static char *
58 1050 error_to_string (GError * error)
59 {
60 2100 g_autofree char *domain_str = NULL;
61
62
2/2
✓ Branch 2 → 3 taken 933 times.
✓ Branch 2 → 5 taken 117 times.
1050 if (!error)
63 933 return g_strdup ("none");
64
65
2/2
✓ Branch 6 → 7 taken 28 times.
✓ Branch 6 → 9 taken 89 times.
117 if (error->domain == FP_DEVICE_RETRY)
66 28 domain_str = g_enum_to_string (FP_TYPE_DEVICE_RETRY, error->code);
67
2/2
✓ Branch 10 → 11 taken 77 times.
✓ Branch 10 → 13 taken 12 times.
89 else if (error->domain == FP_DEVICE_ERROR)
68 77 domain_str = g_enum_to_string (FP_TYPE_DEVICE_ERROR, error->code);
69
1/2
✓ Branch 14 → 15 taken 12 times.
✗ Branch 14 → 16 not taken.
12 else if (error->domain == G_IO_ERROR)
70 12 domain_str = g_enum_to_string (g_io_error_enum_get_type (), error->code);
71 else
72 domain_str = g_strdup_printf ("UNKNOWN_ERROR_%u", error->domain);
73
74 117 return g_strdup_printf ("[%s] %s", domain_str, error->message);
75 }
76
77 /**
78 * fpi_device_emulation_mode_enabled:
79 * @device: The #FpDevice to check
80 *
81 * Checks if the device is running in emulation mode, which is enabled by
82 * setting the FP_DEVICE_EMULATION environment variable to a '1' value but
83 * only when the test emulation library is loaded.
84 * This is used by some drivers to enable special behavior for testing
85 * and development purposes.
86 */
87 gboolean
88 49 (fpi_device_emulation_mode_enabled) (FpDevice *device)
89 {
90 49 static gboolean (*real_fn)(FpDevice *) = NULL;
91 49 static gsize emulation_mode = 0;
92
93
3/4
✓ Branch 2 → 3 taken 20 times.
✓ Branch 2 → 25 taken 29 times.
✓ Branch 4 → 5 taken 20 times.
✗ Branch 4 → 25 not taken.
49 if (g_once_init_enter (&emulation_mode))
94 {
95
1/2
✓ Branch 7 → 8 taken 20 times.
✗ Branch 7 → 22 not taken.
20 if (g_strcmp0 (g_getenv (FPI_EMULATION_ENV_VAR), "1") == 0)
96 {
97 20 const char *dirs[] = {
98 FPI_EMULATION_HELPER_BUILDDIR,
99 FPI_EMULATION_HELPER_INSTALLDIR,
100 };
101
102
1/2
✓ Branch 20 → 9 taken 20 times.
✗ Branch 20 → 21 not taken.
20 for (size_t i = 0; i < G_N_ELEMENTS (dirs); ++i)
103 {
104 20 g_autofree char *path = NULL;
105 g_autoptr(GModule) mod = NULL;
106 20 gpointer sym;
107
108 20 path = g_build_filename (dirs[i], FPI_EMULATION_HELPER_MODULE, NULL);
109
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 20 times.
20 if (!(mod = g_module_open (path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)))
110 continue;
111
112
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 20 times.
20 if (!g_module_symbol (mod, "fpi_device_emulation_mode_enabled", &sym))
113 continue;
114
115 20 real_fn = (gboolean (*)(FpDevice *)) sym;
116 20 g_steal_pointer (&mod);
117 20 break;
118 }
119 }
120
121
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 20 times.
20 g_once_init_leave (&emulation_mode, real_fn ? TRUE : G_MAXSIZE);
122 }
123
124
1/2
✓ Branch 25 → 26 taken 49 times.
✗ Branch 25 → 27 not taken.
49 if (real_fn)
125 49 return real_fn (device);
126
127 return FALSE;
128 }
129
130 /**
131 * fpi_device_class_auto_initialize_features:
132 * @device_class: An #FpDeviceClass to initialize
133 *
134 * Initializes the #FpDeviceClass @features flags checking what device vfuncs
135 * are implemented.
136 * Drivers should call this at the end of the class initialization.
137 */
138 void
139 1636 fpi_device_class_auto_initialize_features (FpDeviceClass *device_class)
140 {
141
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1636 times.
1636 g_return_if_fail (FP_IS_DEVICE_CLASS (device_class));
142
143
2/2
✓ Branch 5 → 6 taken 134 times.
✓ Branch 5 → 7 taken 1502 times.
1636 if (device_class->capture)
144 134 device_class->features |= FP_DEVICE_FEATURE_CAPTURE;
145
146
2/2
✓ Branch 7 → 8 taken 633 times.
✓ Branch 7 → 9 taken 1003 times.
1636 if (device_class->verify)
147 633 device_class->features |= FP_DEVICE_FEATURE_VERIFY;
148
149
2/2
✓ Branch 9 → 10 taken 1383 times.
✓ Branch 9 → 11 taken 253 times.
1636 if (device_class->identify)
150 1383 device_class->features |= FP_DEVICE_FEATURE_IDENTIFY | FP_DEVICE_FEATURE_VERIFY;
151
152
2/2
✓ Branch 11 → 12 taken 1133 times.
✓ Branch 11 → 13 taken 503 times.
1636 if (device_class->list)
153 1133 device_class->features |= FP_DEVICE_FEATURE_STORAGE_LIST;
154
155
2/2
✓ Branch 13 → 14 taken 1257 times.
✓ Branch 13 → 15 taken 379 times.
1636 if (device_class->delete)
156 1257 device_class->features |= FP_DEVICE_FEATURE_STORAGE_DELETE;
157
158
2/2
✓ Branch 15 → 16 taken 1133 times.
✓ Branch 15 → 17 taken 503 times.
1636 if (device_class->clear_storage)
159 1133 device_class->features |= FP_DEVICE_FEATURE_STORAGE_CLEAR;
160
161
5/6
✓ Branch 17 → 18 taken 1257 times.
✓ Branch 17 → 21 taken 379 times.
✓ Branch 18 → 19 taken 126 times.
✓ Branch 18 → 20 taken 1131 times.
✓ Branch 19 → 20 taken 126 times.
✗ Branch 19 → 21 not taken.
1636 if (device_class->delete && (device_class->list || device_class->clear_storage))
162 1257 device_class->features |= FP_DEVICE_FEATURE_STORAGE;
163
164
2/2
✓ Branch 21 → 22 taken 1000 times.
✓ Branch 21 → 23 taken 636 times.
1636 if (device_class->temp_hot_seconds < 0)
165 1000 device_class->features |= FP_DEVICE_FEATURE_ALWAYS_ON;
166 }
167
168 /**
169 * fpi_device_retry_new:
170 * @error: The #FpDeviceRetry error value describing the issue
171 *
172 * Create a new retry error code for use with fpi_device_verify_complete()
173 * and similar calls.
174 */
175 GError *
176 92 fpi_device_retry_new (FpDeviceRetry error)
177 {
178 92 const gchar *msg;
179
180
6/6
✓ Branch 2 → 3 taken 11 times.
✓ Branch 2 → 4 taken 37 times.
✓ Branch 2 → 5 taken 15 times.
✓ Branch 2 → 6 taken 1 time.
✓ Branch 2 → 7 taken 1 time.
✓ Branch 2 → 8 taken 27 times.
92 switch (error)
181 {
182 case FP_DEVICE_RETRY_GENERAL:
183 msg = "Please try again.";
184 break;
185
186 case FP_DEVICE_RETRY_TOO_SHORT:
187 92 msg = "The swipe was too short, please try again.";
188 break;
189
190 37 case FP_DEVICE_RETRY_CENTER_FINGER:
191 37 msg = "The finger was not centered properly, please try again.";
192 37 break;
193
194 15 case FP_DEVICE_RETRY_REMOVE_FINGER:
195 15 msg = "Please try again after removing the finger first.";
196 15 break;
197
198 1 case FP_DEVICE_RETRY_TOO_FAST:
199 1 msg = "The swipe was too fast, please try again.";
200 1 break;
201
202 1 default:
203 1 g_warning ("Unsupported error, returning general error instead!");
204 1 error = FP_DEVICE_RETRY_GENERAL;
205 1 msg = "Please try again.";
206 }
207
208 92 return g_error_new_literal (FP_DEVICE_RETRY, error, msg);
209 }
210
211 /**
212 * fpi_device_error_new:
213 * @error: The #FpDeviceRetry error value describing the issue
214 *
215 * Create a new error code for use with fpi_device_verify_complete() and
216 * similar calls.
217 */
218 GError *
219 105 fpi_device_error_new (FpDeviceError error)
220 {
221 105 const gchar *msg;
222
223
13/13
✓ Branch 2 → 3 taken 27 times.
✓ Branch 2 → 4 taken 11 times.
✓ Branch 2 → 5 taken 2 times.
✓ Branch 2 → 6 taken 14 times.
✓ Branch 2 → 7 taken 11 times.
✓ Branch 2 → 8 taken 10 times.
✓ Branch 2 → 9 taken 1 time.
✓ Branch 2 → 10 taken 4 times.
✓ Branch 2 → 11 taken 6 times.
✓ Branch 2 → 12 taken 8 times.
✓ Branch 2 → 13 taken 2 times.
✓ Branch 2 → 14 taken 1 time.
✓ Branch 2 → 15 taken 8 times.
105 switch (error)
224 {
225 case FP_DEVICE_ERROR_GENERAL:
226 msg = "An unspecified error occurred!";
227 break;
228
229 case FP_DEVICE_ERROR_NOT_SUPPORTED:
230 105 msg = "The operation is not supported on this device!";
231 break;
232
233 11 case FP_DEVICE_ERROR_NOT_OPEN:
234 11 msg = "The device needs to be opened first!";
235 11 break;
236
237 2 case FP_DEVICE_ERROR_ALREADY_OPEN:
238 2 msg = "The device has already been opened!";
239 2 break;
240
241 14 case FP_DEVICE_ERROR_BUSY:
242 14 msg = "The device is still busy with another operation, please try again later.";
243 14 break;
244
245 11 case FP_DEVICE_ERROR_PROTO:
246 11 msg = "The driver encountered a protocol error with the device.";
247 11 break;
248
249 10 case FP_DEVICE_ERROR_DATA_INVALID:
250 10 msg = "Passed (print) data is not valid.";
251 10 break;
252
253 1 case FP_DEVICE_ERROR_DATA_FULL:
254 1 msg = "On device storage space is full.";
255 1 break;
256
257 4 case FP_DEVICE_ERROR_DATA_NOT_FOUND:
258 4 msg = "Print was not found on the devices storage.";
259 4 break;
260
261 6 case FP_DEVICE_ERROR_DATA_DUPLICATE:
262 6 msg = "This finger has already enrolled, please try a different finger";
263 6 break;
264
265 8 case FP_DEVICE_ERROR_REMOVED:
266 8 msg = "This device has been removed from the system.";
267 8 break;
268
269 2 case FP_DEVICE_ERROR_TOO_HOT:
270 2 msg = "Device disabled to prevent overheating.";
271 2 break;
272
273 1 default:
274 1 g_warning ("Unsupported error, returning general error instead!");
275 1 error = FP_DEVICE_ERROR_GENERAL;
276 1 msg = "An unspecified error occurred!";
277 }
278
279 105 return g_error_new_literal (FP_DEVICE_ERROR, error, msg);
280 }
281
282 /**
283 * fpi_device_retry_new_msg:
284 * @error: The #FpDeviceRetry error value describing the issue
285 * @msg: Custom message to use with printf-style formatting
286 * @...: args for @msg
287 *
288 * Create a new retry error code for use with fpi_device_verify_complete()
289 * and similar calls.
290 */
291 GError *
292 7 fpi_device_retry_new_msg (FpDeviceRetry device_error,
293 const gchar *msg,
294 ...)
295 {
296 7 GError *error;
297 7 va_list args;
298
299 7 va_start (args, msg);
300 7 error = g_error_new_valist (FP_DEVICE_RETRY, device_error, msg, args);
301 7 va_end (args);
302
303 7 return error;
304 }
305
306 /**
307 * fpi_device_error_new_msg:
308 * @error: The #FpDeviceRetry error value describing the issue
309 * @msg: Custom message to use with printf-style formatting
310 * @...: args for @msg
311 *
312 * Create a new error code for use with fpi_device_verify_complete()
313 * and similar calls.
314 */
315 GError *
316 34 fpi_device_error_new_msg (FpDeviceError device_error,
317 const gchar *msg,
318 ...)
319 {
320 34 GError *error;
321 34 va_list args;
322
323 34 va_start (args, msg);
324 34 error = g_error_new_valist (FP_DEVICE_ERROR, device_error, msg, args);
325 34 va_end (args);
326
327 34 return error;
328 }
329
330 /**
331 * fpi_device_set_nr_enroll_stages:
332 * @device: The #FpDevice
333 * @enroll_stages: The number of enroll stages
334 *
335 * Updates the reported number of enroll stages that the device needs.
336 * If all supported devices have the same number of stages, then the
337 * value can simply be set in the class.
338 */
339 void
340 88 fpi_device_set_nr_enroll_stages (FpDevice *device,
341 gint enroll_stages)
342 {
343 88 FpDevicePrivate *priv = fp_device_get_instance_private (device);
344
345
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 88 times.
88 g_return_if_fail (FP_IS_DEVICE (device));
346
2/2
✓ Branch 6 → 7 taken 84 times.
✓ Branch 6 → 8 taken 4 times.
88 g_return_if_fail (enroll_stages > 0);
347
348 84 priv->nr_enroll_stages = enroll_stages;
349 84 g_object_notify (G_OBJECT (device), "nr-enroll-stages");
350 }
351
352 /**
353 * fpi_device_set_scan_type:
354 * @device: The #FpDevice
355 * @scan_type: The scan type of the device
356 *
357 * Updates the the scan type of the device from the default.
358 * If all supported devices have the same scan type, then the
359 * value can simply be set in the class.
360 */
361 void
362 6 fpi_device_set_scan_type (FpDevice *device,
363 FpScanType scan_type)
364 {
365 6 FpDevicePrivate *priv = fp_device_get_instance_private (device);
366
367
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 6 times.
6 g_return_if_fail (FP_IS_DEVICE (device));
368
369 6 priv->scan_type = scan_type;
370 6 g_object_notify (G_OBJECT (device), "scan-type");
371 }
372
373 /**
374 * fpi_device_update_features:
375 * @device: The #FpDevice
376 * @update: The feature flags to update
377 * @value: The value to set the flags to
378 *
379 * Updates the feature flags for the device. This can be used
380 * to runtime detect features that are supported by the device.
381 */
382 void
383 46 fpi_device_update_features (FpDevice *device,
384 FpDeviceFeature update,
385 FpDeviceFeature value)
386 {
387 46 FpDevicePrivate *priv = fp_device_get_instance_private (device);
388
389
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 46 times.
46 g_return_if_fail (FP_IS_DEVICE (device));
390
1/2
✓ Branch 6 → 7 taken 46 times.
✗ Branch 6 → 8 not taken.
46 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE);
391
1/2
✓ Branch 7 → 9 taken 46 times.
✗ Branch 7 → 10 not taken.
46 g_return_if_fail ((value & update) == value);
392
393 46 priv->features = (priv->features & ~update) | (value & update);
394 }
395
396 typedef struct
397 {
398 GSource source;
399 FpDevice *device;
400 } FpDeviceTimeoutSource;
401
402 static void
403 1105 timeout_finalize (GSource *source)
404 {
405 1105 FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source;
406 1105 FpDevicePrivate *priv;
407
408 1105 priv = fp_device_get_instance_private (timeout_source->device);
409 1105 priv->sources = g_slist_remove (priv->sources, source);
410 1105 }
411
412 static gboolean
413 645 timeout_dispatch (GSource *source, GSourceFunc gsource_func, gpointer user_data)
414 {
415 645 FpDeviceTimeoutSource *timeout_source = (FpDeviceTimeoutSource *) source;
416 645 FpTimeoutFunc callback = (FpTimeoutFunc) gsource_func;
417
418 645 callback (timeout_source->device, user_data);
419
420 645 return G_SOURCE_REMOVE;
421 }
422
423 static GSourceFuncs timeout_funcs = {
424 NULL, /* prepare */
425 NULL, /* check */
426 timeout_dispatch,
427 timeout_finalize,
428 NULL, NULL
429 };
430
431 /**
432 * fpi_device_add_timeout:
433 * @device: The #FpDevice
434 * @interval: The interval in milliseconds
435 * @func: The #FpTimeoutFunc to call on timeout
436 * @user_data: (nullable): User data to pass to the callback
437 * @destroy_notify: (nullable): #GDestroyNotify for @user_data
438 *
439 * Register a timeout to run. Drivers should always make sure that timers are
440 * cancelled when appropriate.
441 *
442 * Returns: (transfer none): A newly created and attached #GSource
443 */
444 GSource *
445 1113 fpi_device_add_timeout (FpDevice *device,
446 gint interval,
447 FpTimeoutFunc func,
448 gpointer user_data,
449 GDestroyNotify destroy_notify)
450 {
451 1113 FpDevicePrivate *priv = fp_device_get_instance_private (device);
452 1113 FpDeviceTimeoutSource *source;
453 1113 GMainContext *context;
454
455 1113 source = (FpDeviceTimeoutSource *) g_source_new (&timeout_funcs,
456 sizeof (FpDeviceTimeoutSource));
457 1113 source->device = device;
458
459
2/2
✓ Branch 4 → 5 taken 625 times.
✓ Branch 4 → 6 taken 488 times.
1113 if (priv->current_task)
460 625 context = g_task_get_context (priv->current_task);
461 else
462 488 context = g_main_context_get_thread_default ();
463
464 1113 g_source_attach (&source->source, context);
465 1113 g_source_set_callback (&source->source, (GSourceFunc) func, user_data, destroy_notify);
466 2226 g_source_set_ready_time (&source->source,
467 1113 g_source_get_time (&source->source) + interval * (guint64) 1000);
468 1113 priv->sources = g_slist_prepend (priv->sources, source);
469 1113 g_source_unref (&source->source);
470
471 1113 return &source->source;
472 }
473
474 /**
475 * fpi_device_get_usb_device:
476 * @device: The #FpDevice
477 *
478 * Get the #GUsbDevice for this #FpDevice. Only permissible to call if the
479 * #FpDevice is of type %FP_DEVICE_TYPE_USB.
480 *
481 * Returns: The #GUsbDevice
482 */
483 GUsbDevice *
484 13107 fpi_device_get_usb_device (FpDevice *device)
485 {
486 13107 FpDevicePrivate *priv = fp_device_get_instance_private (device);
487
488
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 13107 times.
13107 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
489
2/2
✓ Branch 6 → 7 taken 13106 times.
✓ Branch 6 → 8 taken 1 time.
13107 g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_USB, NULL);
490
491 13106 return priv->usb_device;
492 }
493
494 /**
495 * fpi_device_get_udev_data:
496 * @device: The #FpDevice
497 * @subtype: Which subtype to get information about
498 *
499 * Get a subtype-specific hardware resource for this #FpDevice. Only permissible to call if the
500 * #FpDevice is of type %FP_DEVICE_TYPE_UDEV.
501 *
502 * Returns: Depends on @subtype; for SPIDEV/HIDRAW returns a path to the relevant device.
503 */
504 gpointer
505 1 fpi_device_get_udev_data (FpDevice *device, FpiDeviceUdevSubtypeFlags subtype)
506 {
507 1 FpDevicePrivate *priv = fp_device_get_instance_private (device);
508
509
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
1 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
510
1/2
✓ Branch 6 → 7 taken 1 time.
✗ Branch 6 → 8 not taken.
1 g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_UDEV, NULL);
511
512
1/3
✗ Branch 7 → 9 not taken.
✓ Branch 7 → 10 taken 1 time.
✗ Branch 7 → 11 not taken.
1 switch (subtype)
513 {
514 case FPI_DEVICE_UDEV_SUBTYPE_HIDRAW:
515 return priv->udev_data.hidraw_path;
516
517 1 case FPI_DEVICE_UDEV_SUBTYPE_SPIDEV:
518 1 return priv->udev_data.spidev_path;
519
520 default:
521 g_return_val_if_reached (NULL);
522 return NULL;
523 }
524 }
525
526 /**
527 * fpi_device_get_virtual_env:
528 * @device: The #FpDevice
529 *
530 * Get the value of the environment variable that caused the virtual #FpDevice to be
531 * generated. Only permissible to call if the #FpDevice is of type %FP_DEVICE_TYPE_VIRTUAL.
532 *
533 * Returns: The value of the environment variable
534 */
535 const gchar *
536 116 fpi_device_get_virtual_env (FpDevice *device)
537 {
538 116 FpDevicePrivate *priv = fp_device_get_instance_private (device);
539
540
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 116 times.
116 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
541
2/2
✓ Branch 6 → 7 taken 115 times.
✓ Branch 6 → 8 taken 1 time.
116 g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_VIRTUAL, NULL);
542
543 115 return priv->virtual_env;
544 }
545
546 /**
547 * fpi_device_get_current_action:
548 * @device: The #FpDevice
549 *
550 * Get the currently ongoing action or %FPI_DEVICE_ACTION_NONE if there
551 * is no operation at this time.
552 *
553 * This is useful for drivers that might share code paths between different
554 * actions (e.g. verify and identify) and want to find out again later which
555 * action was started in the beginning.
556 *
557 * Returns: The ongoing #FpiDeviceAction
558 */
559 FpiDeviceAction
560 2115 fpi_device_get_current_action (FpDevice *device)
561 {
562 2115 FpDevicePrivate *priv = fp_device_get_instance_private (device);
563
564
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 2115 times.
2115 g_return_val_if_fail (FP_IS_DEVICE (device), FPI_DEVICE_ACTION_NONE);
565
566 2115 return priv->current_action;
567 }
568
569 /**
570 * fpi_device_action_is_cancelled:
571 * @device: The #FpDevice
572 *
573 * Checks whether the current action has been cancelled by the user.
574 * This is equivalent to first getting the cancellable using
575 * fpi_device_get_cancellable() and then checking whether it has been
576 * cancelled (if it is non-NULL).
577 *
578 * Returns: %TRUE if action should be cancelled
579 */
580 gboolean
581 84 fpi_device_action_is_cancelled (FpDevice *device)
582 {
583 84 FpDevicePrivate *priv = fp_device_get_instance_private (device);
584
585
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 84 times.
84 g_return_val_if_fail (FP_IS_DEVICE (device), TRUE);
586
2/2
✓ Branch 6 → 7 taken 83 times.
✓ Branch 6 → 8 taken 1 time.
84 g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, TRUE);
587
588 83 return g_cancellable_is_cancelled (priv->current_cancellable);
589 }
590
591 /**
592 * fpi_device_get_driver_data:
593 * @device: The #FpDevice
594 *
595 * Returns: The driver data from the #FpIdEntry table entry
596 */
597 guint64
598 792682 fpi_device_get_driver_data (FpDevice *device)
599 {
600 792682 FpDevicePrivate *priv = fp_device_get_instance_private (device);
601
602
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 792682 times.
792682 g_return_val_if_fail (FP_IS_DEVICE (device), 0);
603
604 792682 return priv->driver_data;
605 }
606
607 /**
608 * fpi_device_get_enroll_data:
609 * @device: The #FpDevice
610 * @print: (out) (transfer none): The user provided template print
611 *
612 * Get data for enrollment.
613 */
614 void
615 258 fpi_device_get_enroll_data (FpDevice *device,
616 FpPrint **print)
617 {
618 258 FpDevicePrivate *priv = fp_device_get_instance_private (device);
619 258 FpEnrollData *data;
620
621
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 258 times.
258 g_return_if_fail (FP_IS_DEVICE (device));
622
1/2
✓ Branch 6 → 7 taken 258 times.
✗ Branch 6 → 9 not taken.
258 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
623
624 258 data = g_task_get_task_data (priv->current_task);
625
1/2
✓ Branch 8 → 10 taken 258 times.
✗ Branch 8 → 11 not taken.
258 g_assert (data);
626
627
1/2
✓ Branch 10 → 12 taken 258 times.
✗ Branch 10 → 13 not taken.
258 if (print)
628 258 *print = data->print;
629 }
630
631 /**
632 * fpi_device_get_capture_data:
633 * @device: The #FpDevice
634 * @wait_for_finger: (out): Whether to wait for finger or not
635 *
636 * Get data for capture.
637 */
638 void
639 19 fpi_device_get_capture_data (FpDevice *device,
640 gboolean *wait_for_finger)
641 {
642 19 FpDevicePrivate *priv = fp_device_get_instance_private (device);
643
644
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 19 times.
19 g_return_if_fail (FP_IS_DEVICE (device));
645
1/2
✓ Branch 6 → 7 taken 19 times.
✗ Branch 6 → 8 not taken.
19 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE);
646
647
1/2
✓ Branch 7 → 9 taken 19 times.
✗ Branch 7 → 10 not taken.
19 if (wait_for_finger)
648 19 *wait_for_finger = priv->wait_for_finger;
649 }
650
651 /**
652 * fpi_device_get_verify_data:
653 * @device: The #FpDevice
654 * @print: (out) (transfer none): The enrolled print
655 *
656 * Get data for verify.
657 */
658 void
659 29 fpi_device_get_verify_data (FpDevice *device,
660 FpPrint **print)
661 {
662 29 FpDevicePrivate *priv = fp_device_get_instance_private (device);
663 29 FpMatchData *data;
664
665
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 29 times.
29 g_return_if_fail (FP_IS_DEVICE (device));
666
1/2
✓ Branch 6 → 7 taken 29 times.
✗ Branch 6 → 9 not taken.
29 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
667
668 29 data = g_task_get_task_data (priv->current_task);
669
1/2
✓ Branch 8 → 10 taken 29 times.
✗ Branch 8 → 11 not taken.
29 g_assert (data);
670
671
1/2
✓ Branch 10 → 12 taken 29 times.
✗ Branch 10 → 13 not taken.
29 if (print)
672 29 *print = data->enrolled_print;
673 }
674
675 /**
676 * fpi_device_get_identify_data:
677 * @device: The #FpDevice
678 * @prints: (out) (transfer none) (element-type FpPrint): The gallery of prints
679 *
680 * Get prints gallery for identification.
681 *
682 * The @prints array is always non-%NULL and may contain a list of #FpPrint's
683 * that the device should match against.
684 *
685 * Note that @prints can be an empty array, in such case the device is expected
686 * to report the scanned print matching the one in its internal storage, if any.
687 *
688 */
689 void
690 65 fpi_device_get_identify_data (FpDevice *device,
691 GPtrArray **prints)
692 {
693 65 FpDevicePrivate *priv = fp_device_get_instance_private (device);
694 65 FpMatchData *data;
695
696
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 65 times.
65 g_return_if_fail (FP_IS_DEVICE (device));
697
1/2
✓ Branch 6 → 7 taken 65 times.
✗ Branch 6 → 9 not taken.
65 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
698
699 65 data = g_task_get_task_data (priv->current_task);
700
1/2
✓ Branch 8 → 10 taken 65 times.
✗ Branch 8 → 11 not taken.
65 g_assert (data);
701
702
1/2
✓ Branch 10 → 12 taken 65 times.
✗ Branch 10 → 13 not taken.
65 if (prints)
703 65 *prints = data->gallery;
704 }
705
706 /**
707 * fpi_device_get_delete_data:
708 * @device: The #FpDevice
709 * @print: (out) (transfer none): The print to delete
710 *
711 * Get data for delete.
712 */
713 void
714 28 fpi_device_get_delete_data (FpDevice *device,
715 FpPrint **print)
716 {
717 28 FpDevicePrivate *priv = fp_device_get_instance_private (device);
718
719
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 28 times.
28 g_return_if_fail (FP_IS_DEVICE (device));
720
1/2
✓ Branch 6 → 7 taken 28 times.
✗ Branch 6 → 8 not taken.
28 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE);
721
722
1/2
✓ Branch 7 → 9 taken 28 times.
✗ Branch 7 → 11 not taken.
28 if (print)
723 28 *print = g_task_get_task_data (priv->current_task);
724 }
725
726 /**
727 * fpi_device_get_cancellable:
728 * @device: The #FpDevice
729 *
730 * Retrieve the #GCancellable that may cancel the currently ongoing operation. This
731 * is primarily useful to pass directly to e.g. fpi_usb_transfer_submit() for cancellable
732 * transfers.
733 * In many cases the cancel vfunc may be more convenient to react to cancellation in some
734 * way.
735 *
736 * Returns: (transfer none): The #GCancellable for the current action.
737 */
738 GCancellable *
739 3270 fpi_device_get_cancellable (FpDevice *device)
740 {
741 3270 FpDevicePrivate *priv = fp_device_get_instance_private (device);
742
743
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3270 times.
3270 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
744
2/2
✓ Branch 6 → 7 taken 3269 times.
✓ Branch 6 → 8 taken 1 time.
3270 g_return_val_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE, NULL);
745
746 3269 return priv->current_cancellable;
747 }
748
749 static void
750 4 emit_removed_on_task_completed (FpDevice *device)
751 {
752 4 g_signal_emit_by_name (device, "removed");
753 4 }
754
755 /**
756 * fpi_device_remove:
757 * @device: The #FpDevice
758 *
759 * Called to signal to the #FpDevice that it has been unplugged (physically
760 * removed from the system).
761 *
762 * For USB devices, this API is called automatically by #FpContext.
763 */
764 void
765 7 fpi_device_remove (FpDevice *device)
766 {
767 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
768
769
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
7 g_return_if_fail (FP_IS_DEVICE (device));
770
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 9 not taken.
7 g_return_if_fail (!priv->is_removed);
771
772 7 priv->is_removed = TRUE;
773
774 7 g_object_notify (G_OBJECT (device), "removed");
775
776 /* If there is a pending action, we wait for it to fail, otherwise we
777 * immediately emit the "removed" signal. */
778
2/2
✓ Branch 8 → 10 taken 4 times.
✓ Branch 8 → 11 taken 3 times.
7 if (priv->current_task)
779 {
780 4 g_signal_connect_object (priv->current_task,
781 "notify::completed",
782 (GCallback) emit_removed_on_task_completed,
783 device,
784 G_CONNECT_SWAPPED);
785 }
786 else
787 {
788 3 g_signal_emit_by_name (device, "removed");
789 }
790 }
791
792 /**
793 * fpi_device_action_error:
794 * @device: The #FpDevice
795 * @error: (nullable) (transfer full): The #GError or %NULL on success
796 *
797 * Finish an ongoing action with an error. This is the same as calling
798 * the corresponding complete function such as fpi_device_open_complete()
799 * with an error set. If possible, use the correct complete function as
800 * that results in improved error detection.
801 */
802 void
803 29 fpi_device_action_error (FpDevice *device,
804 GError *error)
805 {
806 29 FpDevicePrivate *priv = fp_device_get_instance_private (device);
807
808
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 29 times.
29 g_return_if_fail (FP_IS_DEVICE (device));
809
2/2
✓ Branch 6 → 7 taken 28 times.
✓ Branch 6 → 8 taken 1 time.
29 g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
810
811
2/2
✓ Branch 7 → 9 taken 19 times.
✓ Branch 7 → 17 taken 9 times.
28 if (error != NULL)
812 {
813
1/2
✓ Branch 10 → 11 taken 19 times.
✗ Branch 10 → 19 not taken.
19 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
814 {
815 38 g_autofree char *error_str = error_to_string (error);
816 38 g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
817
818 19 g_debug ("Device reported generic error (%s) during action; action was: %s",
819 error_str, action_str);
820 }
821 }
822 else
823 {
824 9 g_warning ("Device failed to pass an error to generic action error function");
825 9 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, "Device reported error but did not provide an error condition");
826 }
827
828
829
10/11
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 22 taken 2 times.
✓ Branch 19 → 24 taken 2 times.
✓ Branch 19 → 26 taken 7 times.
✓ Branch 19 → 28 taken 3 times.
✓ Branch 19 → 30 taken 4 times.
✓ Branch 19 → 32 taken 3 times.
✓ Branch 19 → 34 taken 2 times.
✓ Branch 19 → 36 taken 2 times.
✓ Branch 19 → 38 taken 2 times.
✗ Branch 19 → 40 not taken.
28 switch (priv->current_action)
830 {
831 1 case FPI_DEVICE_ACTION_PROBE:
832 1 fpi_device_probe_complete (device, NULL, NULL, error);
833 1 break;
834
835 2 case FPI_DEVICE_ACTION_OPEN:
836 2 fpi_device_open_complete (device, error);
837 2 break;
838
839 2 case FPI_DEVICE_ACTION_CLOSE:
840 2 fpi_device_close_complete (device, error);
841 2 break;
842
843 7 case FPI_DEVICE_ACTION_ENROLL:
844 7 fpi_device_enroll_complete (device, NULL, error);
845 7 break;
846
847 3 case FPI_DEVICE_ACTION_VERIFY:
848 3 fpi_device_verify_complete (device, error);
849 3 break;
850
851 4 case FPI_DEVICE_ACTION_IDENTIFY:
852 4 fpi_device_identify_complete (device, error);
853 4 break;
854
855 3 case FPI_DEVICE_ACTION_CAPTURE:
856 3 fpi_device_capture_complete (device, NULL, error);
857 3 break;
858
859 2 case FPI_DEVICE_ACTION_DELETE:
860 2 fpi_device_delete_complete (device, error);
861 2 break;
862
863 2 case FPI_DEVICE_ACTION_LIST:
864 2 fpi_device_list_complete (device, NULL, error);
865 2 break;
866
867 2 case FPI_DEVICE_ACTION_CLEAR_STORAGE:
868 2 fpi_device_clear_storage_complete (device, error);
869 2 break;
870
871 default:
872 case FPI_DEVICE_ACTION_NONE:
873 g_return_if_reached ();
874 break;
875 }
876 }
877
878 /**
879 * fpi_device_critical_enter:
880 * @device: The #FpDevice
881 *
882 * Enter a critical section in the driver code where no outside calls from
883 * libfprint should happen. Drivers can already assume that everything
884 * happens from the same thread, however, that still allows e.g. the cancel
885 * vfunc to be called at any point in time.
886 *
887 * Using this kind of critical section, the driver can assume that libfprint
888 * will not forward any external requests to the driver for the time being.
889 * This is for example useful to prevent cancellation while the device is being
890 * set up. Or, said differently, using this feature means that the cancel
891 * handler is able to make more assumptions about the current state.
892 *
893 * Please note that the driver is not shielded from all external changes. For
894 * example the cancellable as returned by fpi_device_get_cancellable() will
895 * still change immediately.
896 *
897 * The driver may call this function multiple times, but must also ensure that
898 * fpi_device_critical_leave() is called an equal amount of times and that all
899 * critical sections are left before command completion.
900 */
901 void
902 60 fpi_device_critical_enter (FpDevice *device)
903 {
904 60 FpDevicePrivate *priv = fp_device_get_instance_private (device);
905
906
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 60 times.
60 g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
907
908 60 priv->critical_section += 1;
909
910 /* Stop flushing events if that was previously queued. */
911
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 58 times.
60 if (priv->critical_section_flush_source)
912 2 g_source_destroy (priv->critical_section_flush_source);
913 60 priv->critical_section_flush_source = NULL;
914 }
915
916 static gboolean
917 59 fpi_device_critical_section_flush_idle_cb (FpDevice *device)
918 {
919 59 FpDevicePrivate *priv = fp_device_get_instance_private (device);
920
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 8 taken 58 times.
59 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
921
922
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 8 taken 58 times.
59 if (priv->cancel_queued)
923 {
924 /* Cancellation must only happen if the driver is busy. */
925
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 7 not taken.
1 if (priv->current_action != FPI_DEVICE_ACTION_NONE &&
926
1/2
✓ Branch 5 → 6 taken 1 time.
✗ Branch 5 → 7 not taken.
1 priv->current_task_idle_return_source == NULL)
927 1 cls->cancel (device);
928 1 priv->cancel_queued = FALSE;
929
930 1 return G_SOURCE_CONTINUE;
931 }
932
933
2/2
✓ Branch 8 → 9 taken 2 times.
✓ Branch 8 → 11 taken 56 times.
58 if (priv->suspend_queued)
934 {
935 2 priv->suspend_queued = FALSE;
936 2 fpi_device_suspend (device);
937
938 2 return G_SOURCE_CONTINUE;
939 }
940
941
2/2
✓ Branch 11 → 12 taken 1 time.
✓ Branch 11 → 14 taken 55 times.
56 if (priv->resume_queued)
942 {
943 1 priv->resume_queued = FALSE;
944 1 fpi_device_resume (device);
945
946 1 return G_SOURCE_CONTINUE;
947 }
948
949 55 priv->critical_section_flush_source = NULL;
950
951 55 return G_SOURCE_REMOVE;
952 }
953
954 /**
955 * fpi_device_critical_leave:
956 * @device: The #FpDevice
957 *
958 * Leave a critical section started by fpi_device_critical_enter().
959 *
960 * Once all critical sections have been left, libfprint will start flushing
961 * out the queued up requests. This is done from the mainloop and the driver
962 * is protected from reentrency issues.
963 */
964 void
965 60 fpi_device_critical_leave (FpDevice *device)
966 {
967 60 FpDevicePrivate *priv = fp_device_get_instance_private (device);
968
969
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 60 times.
60 g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
970
1/2
✓ Branch 5 → 6 taken 60 times.
✗ Branch 5 → 7 not taken.
60 g_return_if_fail (priv->critical_section);
971
972 60 priv->critical_section -= 1;
973
2/2
✓ Branch 6 → 8 taken 57 times.
✓ Branch 6 → 16 taken 3 times.
60 if (priv->critical_section)
974 return;
975
976 /* We left the critical section, make sure a flush is queued. */
977
1/2
✓ Branch 8 → 9 taken 57 times.
✗ Branch 8 → 16 not taken.
57 if (priv->critical_section_flush_source)
978 return;
979
980 57 priv->critical_section_flush_source = g_idle_source_new ();
981 57 g_source_set_priority (priv->critical_section_flush_source, G_PRIORITY_HIGH);
982 57 g_source_set_callback (priv->critical_section_flush_source,
983 (GSourceFunc) fpi_device_critical_section_flush_idle_cb,
984 device,
985 NULL);
986 57 g_source_set_name (priv->critical_section_flush_source,
987 "Flush libfprint driver critical section");
988 57 g_source_attach (priv->critical_section_flush_source,
989 g_task_get_context (priv->current_task));
990 57 g_source_unref (priv->critical_section_flush_source);
991 }
992
993 static void
994 925 clear_device_cancel_action (FpDevice *device)
995 {
996 925 FpDevicePrivate *priv = fp_device_get_instance_private (device);
997
998
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 921 times.
925 g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy);
999
1000
2/2
✓ Branch 5 → 6 taken 861 times.
✓ Branch 5 → 8 taken 64 times.
925 if (priv->current_cancellable_id)
1001 {
1002 861 g_cancellable_disconnect (priv->current_cancellable,
1003 priv->current_cancellable_id);
1004 861 priv->current_cancellable_id = 0;
1005 }
1006
1007
2/2
✓ Branch 8 → 9 taken 179 times.
✓ Branch 8 → 12 taken 746 times.
925 if (priv->current_task_cancellable_id)
1008 {
1009 179 g_cancellable_disconnect (g_task_get_cancellable (priv->current_task),
1010 priv->current_task_cancellable_id);
1011 179 priv->current_task_cancellable_id = 0;
1012 }
1013 925 }
1014
1015 typedef enum _FpDeviceTaskReturnType {
1016 FP_DEVICE_TASK_RETURN_INT,
1017 FP_DEVICE_TASK_RETURN_BOOL,
1018 FP_DEVICE_TASK_RETURN_OBJECT,
1019 FP_DEVICE_TASK_RETURN_PTR_ARRAY,
1020 FP_DEVICE_TASK_RETURN_ERROR,
1021 } FpDeviceTaskReturnType;
1022
1023 typedef struct _FpDeviceTaskReturnData
1024 {
1025 FpDevice *device;
1026 FpDeviceTaskReturnType type;
1027 gpointer result;
1028 } FpDeviceTaskReturnData;
1029
1030 static gboolean
1031 925 fp_device_task_return_in_idle_cb (gpointer user_data)
1032 {
1033 1850 g_autoptr(GTask) task = NULL;
1034
1/2
✓ Branch 39 → 40 taken 925 times.
✗ Branch 39 → 41 not taken.
925 g_autoptr(GError) cancellation_reason = NULL;
1035 925 FpDeviceTaskReturnData *data = user_data;
1036 925 FpDevicePrivate *priv = fp_device_get_instance_private (data->device);
1037 925 FpiDeviceAction action;
1038
1039
1/2
✓ Branch 4 → 5 taken 925 times.
✗ Branch 4 → 9 not taken.
925 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1040 {
1041 1850 g_autofree char *action_str = g_enum_to_string (FPI_TYPE_DEVICE_ACTION, priv->current_action);
1042
1043 925 g_debug ("Completing action %s in idle!", action_str);
1044 }
1045
1046
1/2
✓ Branch 9 → 10 taken 925 times.
✗ Branch 9 → 11 not taken.
925 task = g_steal_pointer (&priv->current_task);
1047 925 action = priv->current_action;
1048 925 priv->current_action = FPI_DEVICE_ACTION_NONE;
1049 925 priv->current_task_idle_return_source = NULL;
1050
1/2
✓ Branch 9 → 10 taken 925 times.
✗ Branch 9 → 11 not taken.
925 g_clear_object (&priv->current_cancellable);
1051 925 cancellation_reason = g_steal_pointer (&priv->current_cancellation_reason);
1052
1053 925 fpi_device_update_temp (data->device, FALSE);
1054
1055
2/2
✓ Branch 12 → 13 taken 220 times.
✓ Branch 12 → 15 taken 705 times.
925 if (action == FPI_DEVICE_ACTION_OPEN &&
1056
2/2
✓ Branch 13 → 14 taken 213 times.
✓ Branch 13 → 15 taken 7 times.
220 data->type != FP_DEVICE_TASK_RETURN_ERROR)
1057 {
1058 213 priv->is_open = TRUE;
1059 213 g_object_notify (G_OBJECT (data->device), "open");
1060 }
1061
2/2
✓ Branch 15 → 16 taken 213 times.
✓ Branch 15 → 17 taken 499 times.
712 else if (action == FPI_DEVICE_ACTION_CLOSE)
1062 {
1063 /* Always consider the device closed. Drivers should try hard to close the
1064 * device. Generally, e.g. cancellations should be ignored.
1065 */
1066 213 priv->is_open = FALSE;
1067 213 g_object_notify (G_OBJECT (data->device), "open");
1068 }
1069
1070 /* TODO: Port/use the cancellation mechanism for device removal! */
1071
1072 /* Return FP_DEVICE_ERROR_REMOVED if the device is removed,
1073 * with the exception of a successful open, which is an odd corner case. */
1074
4/4
✓ Branch 17 → 18 taken 9 times.
✓ Branch 17 → 22 taken 916 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 8 times.
925 if (priv->is_removed &&
1075 1 ((action != FPI_DEVICE_ACTION_OPEN) ||
1076
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 22 taken 1 time.
1 (action == FPI_DEVICE_ACTION_OPEN && data->type == FP_DEVICE_TASK_RETURN_ERROR)))
1077 {
1078 8 g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_REMOVED));
1079
1080 /* NOTE: The removed signal will be emitted from the GTask
1081 * notify::completed if that is necessary. */
1082
1083 8 return G_SOURCE_REMOVE;
1084 }
1085
1086
5/6
✓ Branch 22 → 23 taken 15 times.
✓ Branch 22 → 25 taken 688 times.
✓ Branch 22 → 27 taken 72 times.
✓ Branch 22 → 29 taken 48 times.
✓ Branch 22 → 31 taken 94 times.
✗ Branch 22 → 35 not taken.
917 switch (data->type)
1087 {
1088 15 case FP_DEVICE_TASK_RETURN_INT:
1089 15 g_task_return_int (task, GPOINTER_TO_INT (data->result));
1090 15 break;
1091
1092 688 case FP_DEVICE_TASK_RETURN_BOOL:
1093 688 g_task_return_boolean (task, GPOINTER_TO_UINT (data->result));
1094 688 break;
1095
1096 72 case FP_DEVICE_TASK_RETURN_OBJECT:
1097 72 g_task_return_pointer (task, g_steal_pointer (&data->result),
1098 g_object_unref);
1099 72 break;
1100
1101 48 case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
1102 48 g_task_return_pointer (task, g_steal_pointer (&data->result),
1103 (GDestroyNotify) g_ptr_array_unref);
1104 48 break;
1105
1106 94 case FP_DEVICE_TASK_RETURN_ERROR:
1107 /* Return internal cancellation reason instead if we have one.
1108 * Note that an external cancellation always returns G_IO_ERROR_CANCELLED
1109 */
1110
2/2
✓ Branch 31 → 32 taken 2 times.
✓ Branch 31 → 34 taken 92 times.
94 if (cancellation_reason)
1111 {
1112 2 g_task_set_task_data (task, NULL, NULL);
1113 2 g_task_return_error (task, g_steal_pointer (&cancellation_reason));
1114 }
1115 else
1116 {
1117 92 g_task_return_error (task, g_steal_pointer (&data->result));
1118 }
1119 break;
1120
1121 default:
1122 g_assert_not_reached ();
1123 }
1124
1125 return G_SOURCE_REMOVE;
1126 }
1127
1128 static void
1129 925 fpi_device_task_return_data_free (FpDeviceTaskReturnData *data)
1130 {
1131
4/5
✓ Branch 2 → 3 taken 72 times.
✓ Branch 2 → 5 taken 48 times.
✓ Branch 2 → 7 taken 96 times.
✗ Branch 2 → 8 not taken.
✓ Branch 2 → 10 taken 709 times.
925 switch (data->type)
1132 {
1133 case FP_DEVICE_TASK_RETURN_INT:
1134 case FP_DEVICE_TASK_RETURN_BOOL:
1135 break;
1136
1137 72 case FP_DEVICE_TASK_RETURN_OBJECT:
1138
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 10 taken 72 times.
72 g_clear_object ((GObject **) &data->result);
1139 break;
1140
1141 48 case FP_DEVICE_TASK_RETURN_PTR_ARRAY:
1142
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 10 taken 48 times.
48 g_clear_pointer ((GPtrArray **) &data->result, g_ptr_array_unref);
1143 break;
1144
1145 96 case FP_DEVICE_TASK_RETURN_ERROR:
1146 96 g_clear_error ((GError **) &data->result);
1147 96 break;
1148
1149 default:
1150 g_assert_not_reached ();
1151 }
1152
1153 925 g_object_unref (data->device);
1154 925 g_free (data);
1155 925 }
1156
1157 /**
1158 * fpi_device_return_task_in_idle:
1159 * @device: The #FpDevice
1160 * @return_type: The #FpDeviceTaskReturnType of @return_data
1161 * @return_data: (nullable) (transfer full): The data to return.
1162 *
1163 * Completes a #FpDevice task in an idle source, stealing the ownership of
1164 * the passed @returned_data.
1165 */
1166 static void
1167 925 fpi_device_return_task_in_idle (FpDevice *device,
1168 FpDeviceTaskReturnType return_type,
1169 gpointer return_data)
1170 {
1171 925 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1172 925 FpDeviceTaskReturnData *data;
1173
1174 925 data = g_new0 (FpDeviceTaskReturnData, 1);
1175 925 data->device = g_object_ref (device);
1176 925 data->type = return_type;
1177 925 data->result = return_data;
1178
1179 925 priv->current_task_idle_return_source = g_idle_source_new ();
1180 925 g_source_set_priority (priv->current_task_idle_return_source,
1181 g_task_get_priority (priv->current_task));
1182 925 g_source_set_callback (priv->current_task_idle_return_source,
1183 fp_device_task_return_in_idle_cb,
1184 data,
1185 (GDestroyNotify) fpi_device_task_return_data_free);
1186
1187 925 g_source_attach (priv->current_task_idle_return_source,
1188 g_task_get_context (priv->current_task));
1189 925 g_source_unref (priv->current_task_idle_return_source);
1190 925 }
1191
1192 /**
1193 * fpi_device_probe_complete:
1194 * @device: The #FpDevice
1195 * @device_id: Unique ID for the device or %NULL
1196 * @device_name: Human readable name or %NULL for driver name
1197 * @error: (nullable) (transfer full): The #GError or %NULL on success
1198 *
1199 * Finish an ongoing probe operation. If error is %NULL success is assumed.
1200 */
1201 void
1202 151 fpi_device_probe_complete (FpDevice *device,
1203 const gchar *device_id,
1204 const gchar *device_name,
1205 GError *error)
1206 {
1207 151 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1208
1209
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 151 times.
151 g_return_if_fail (FP_IS_DEVICE (device));
1210
2/2
✓ Branch 6 → 7 taken 150 times.
✓ Branch 6 → 9 taken 1 time.
151 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_PROBE);
1211
1212
1/2
✓ Branch 8 → 10 taken 150 times.
✗ Branch 8 → 13 not taken.
150 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1213 {
1214 300 g_autofree char *error_str = error_to_string (error);
1215
1216 150 g_debug ("Device reported probe completion (ID: %s, name: %s, error: %s)",
1217 device_id, device_name, error_str);
1218 }
1219
1220 150 clear_device_cancel_action (device);
1221 150 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1222
1223
2/2
✓ Branch 15 → 16 taken 148 times.
✓ Branch 15 → 33 taken 2 times.
150 if (!error)
1224 {
1225
2/2
✓ Branch 16 → 17 taken 11 times.
✓ Branch 16 → 24 taken 137 times.
148 if (device_id)
1226 {
1227
1/2
✓ Branch 17 → 18 taken 11 times.
✗ Branch 17 → 19 not taken.
11 g_clear_pointer (&priv->device_id, g_free);
1228
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 22 taken 11 times.
11 priv->device_id = g_strdup (device_id);
1229 11 g_object_notify (G_OBJECT (device), "device-id");
1230 }
1231
2/2
✓ Branch 24 → 25 taken 6 times.
✓ Branch 24 → 32 taken 142 times.
148 if (device_name)
1232 {
1233
1/2
✓ Branch 25 → 26 taken 6 times.
✗ Branch 25 → 27 not taken.
6 g_clear_pointer (&priv->device_name, g_free);
1234
1/2
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 30 taken 6 times.
6 priv->device_name = g_strdup (device_name);
1235 6 g_object_notify (G_OBJECT (device), "name");
1236 }
1237 148 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1238 GUINT_TO_POINTER (TRUE));
1239 }
1240 else
1241 {
1242 2 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1243 }
1244 }
1245
1246 /**
1247 * fpi_device_open_complete:
1248 * @device: The #FpDevice
1249 * @error: (nullable) (transfer full): The #GError or %NULL on success
1250 *
1251 * Finish an ongoing open operation. If error is %NULL success is assumed.
1252 */
1253 void
1254 221 fpi_device_open_complete (FpDevice *device, GError *error)
1255 {
1256 221 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1257
1258
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 221 times.
221 g_return_if_fail (FP_IS_DEVICE (device));
1259
2/2
✓ Branch 6 → 7 taken 220 times.
✓ Branch 6 → 9 taken 1 time.
221 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_OPEN);
1260
1261
1/2
✓ Branch 8 → 10 taken 220 times.
✗ Branch 8 → 13 not taken.
220 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1262 {
1263 440 g_autofree char *error_str = error_to_string (error);
1264
1265 220 g_debug ("Device reported open completion (error: %s)", error_str);
1266 }
1267
1268 220 clear_device_cancel_action (device);
1269 220 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1270
1271
2/2
✓ Branch 15 → 16 taken 213 times.
✓ Branch 15 → 17 taken 7 times.
220 if (!error)
1272 213 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1273 GUINT_TO_POINTER (TRUE));
1274 else
1275 7 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1276 }
1277
1278 /**
1279 * fpi_device_close_complete:
1280 * @device: The #FpDevice
1281 * @error: (nullable) (transfer full): The #GError or %NULL on success
1282 *
1283 * Finish an ongoing close operation. If error is %NULL success is assumed.
1284 */
1285 void
1286 214 fpi_device_close_complete (FpDevice *device, GError *error)
1287 {
1288 214 g_autoptr(GError) nested_error = NULL;
1289 214 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1290
1291
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 214 times.
214 g_return_if_fail (FP_IS_DEVICE (device));
1292
2/2
✓ Branch 6 → 7 taken 213 times.
✓ Branch 6 → 9 taken 1 time.
214 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLOSE);
1293
1294
1/2
✓ Branch 8 → 10 taken 213 times.
✗ Branch 8 → 13 not taken.
213 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1295 {
1296 426 g_autofree char *error_str = error_to_string (error);
1297
1298 213 g_debug ("Device reported close completion (error: %s)", error_str);
1299 }
1300
1301 213 clear_device_cancel_action (device);
1302 213 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1303
1304
2/3
✓ Branch 15 → 16 taken 29 times.
✗ Branch 15 → 21 not taken.
✓ Branch 15 → 22 taken 184 times.
213 switch (priv->type)
1305 {
1306 29 case FP_DEVICE_TYPE_USB:
1307
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 22 taken 29 times.
29 if (!g_usb_device_close (priv->usb_device, &nested_error))
1308 {
1309 if (error == NULL)
1310 error = g_steal_pointer (&nested_error);
1311
1312 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1313 return;
1314 }
1315 break;
1316
1317 case FP_DEVICE_TYPE_VIRTUAL:
1318 case FP_DEVICE_TYPE_UDEV:
1319 break;
1320
1321 default:
1322 g_assert_not_reached ();
1323 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1324 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1325 return;
1326 }
1327
1328
2/2
✓ Branch 22 → 23 taken 208 times.
✓ Branch 22 → 24 taken 5 times.
213 if (!error)
1329 208 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1330 GUINT_TO_POINTER (TRUE));
1331 else
1332 5 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1333 }
1334
1335 /**
1336 * fpi_device_enroll_complete:
1337 * @device: The #FpDevice
1338 * @print: (nullable) (transfer full): The #FpPrint or %NULL on failure
1339 * @error: (nullable) (transfer full): The #GError or %NULL on success
1340 *
1341 * Finish an ongoing enroll operation. The #FpPrint can be stored by the
1342 * caller for later verification.
1343 */
1344 void
1345 68 fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
1346 {
1347 68 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1348
1349
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 68 times.
68 g_return_if_fail (FP_IS_DEVICE (device));
1350
2/2
✓ Branch 6 → 7 taken 67 times.
✓ Branch 6 → 9 taken 1 time.
68 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
1351
1352
1/2
✓ Branch 8 → 10 taken 67 times.
✗ Branch 8 → 13 not taken.
67 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1353 {
1354 134 g_autofree char *error_str = error_to_string (error);
1355
1356 67 g_debug ("Device reported enroll completion (print: %p, error: %s)",
1357 print, error_str);
1358 }
1359
1360 67 clear_device_cancel_action (device);
1361 67 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1362
1363
2/2
✓ Branch 15 → 16 taken 57 times.
✓ Branch 15 → 38 taken 10 times.
67 if (!error)
1364 {
1365
2/2
✓ Branch 17 → 18 taken 56 times.
✓ Branch 17 → 35 taken 1 time.
57 if (FP_IS_PRINT (print))
1366 {
1367 56 FpiPrintType print_type;
1368
1369 56 g_object_get (print, "fpi-type", &print_type, NULL);
1370
2/2
✓ Branch 19 → 20 taken 1 time.
✓ Branch 19 → 26 taken 55 times.
56 if (print_type == FPI_PRINT_UNDEFINED)
1371 {
1372 1 g_warning ("Driver did not set the type on the returned print!");
1373
1/2
✓ Branch 21 → 22 taken 1 time.
✗ Branch 21 → 23 not taken.
1 g_clear_object (&print);
1374
1375 1 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1376 "Driver provided incorrect print data!");
1377 1 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1378 1 return;
1379 }
1380
1381
1/2
✓ Branch 27 → 28 taken 55 times.
✗ Branch 27 → 33 not taken.
55 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1382 {
1383 110 g_autofree char *finger_str = g_enum_to_string (FP_TYPE_FINGER, fp_print_get_finger (print));
1384
1385 55 g_debug ("Print for finger %s enrolled", finger_str);
1386 }
1387
1388 55 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, print);
1389 }
1390 else
1391 {
1392 1 g_warning ("Driver did not provide a valid print and failed to provide an error!");
1393 1 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1394 "Driver failed to provide print data!");
1395 1 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1396 }
1397 }
1398 else
1399 {
1400 10 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1401
2/2
✓ Branch 40 → 41 taken 1 time.
✓ Branch 40 → 43 taken 9 times.
10 if (FP_IS_PRINT (print))
1402 {
1403 1 g_warning ("Driver passed an error but also provided a print, returning error!");
1404 1 g_object_unref (print);
1405 }
1406 }
1407 }
1408
1409 /**
1410 * fpi_device_verify_complete:
1411 * @device: The #FpDevice
1412 * @error: A #GError if result is %FPI_MATCH_ERROR
1413 *
1414 * Finish an ongoing verify operation.
1415 *
1416 * Note that @error should only be set for actual errors. In the case
1417 * of retry errors, report these using fpi_device_verify_report()
1418 * and then call this function without any error argument.
1419 *
1420 * If @error is not set, we expect that a result (and print, in case)
1421 * have been already reported via fpi_device_verify_report().
1422 */
1423 void
1424 39 fpi_device_verify_complete (FpDevice *device,
1425 GError *error)
1426 {
1427 39 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1428 39 FpMatchData *data;
1429
1430
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 39 times.
39 g_return_if_fail (FP_IS_DEVICE (device));
1431
2/2
✓ Branch 6 → 7 taken 38 times.
✓ Branch 6 → 9 taken 1 time.
39 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
1432
1433
1/2
✓ Branch 8 → 10 taken 38 times.
✗ Branch 8 → 13 not taken.
38 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1434 {
1435 76 g_autofree char *error_str = error_to_string (error);
1436
1437 38 g_debug ("Device reported verify completion (error: %s)", error_str);
1438 }
1439
1440 38 data = g_task_get_task_data (priv->current_task);
1441
1442 38 clear_device_cancel_action (device);
1443 38 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1444
1445
2/2
✓ Branch 16 → 17 taken 27 times.
✓ Branch 16 → 26 taken 11 times.
38 if (!error)
1446 {
1447
2/2
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 21 taken 26 times.
27 if (!data->result_reported)
1448 {
1449 1 g_warning ("Driver reported successful verify complete but did not report the result earlier. Reporting error instead");
1450 1 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1451 1 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1452 }
1453
2/2
✓ Branch 21 → 22 taken 11 times.
✓ Branch 21 → 23 taken 15 times.
26 else if (data->error)
1454 {
1455 11 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error));
1456 }
1457 else
1458 {
1459 15 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT,
1460
2/2
✓ Branch 23 → 24 taken 7 times.
✓ Branch 23 → 25 taken 8 times.
15 GINT_TO_POINTER (data->match != NULL ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL));
1461 }
1462 }
1463 else
1464 {
1465 /* Replace a retry error with a general error, this is a driver bug. */
1466
2/2
✓ Branch 27 → 28 taken 2 times.
✓ Branch 27 → 32 taken 9 times.
11 if (error->domain == FP_DEVICE_RETRY)
1467 {
1468 2 g_warning ("Driver reported a retry error to fpi_device_verify_complete. "
1469 "This is not permissible and needs to be reported using "
1470 "fpi_device_verify_report, reporting general verification "
1471 "failure instead.");
1472 2 g_clear_error (&error);
1473 2 error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL);
1474 }
1475 11 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1476 }
1477 }
1478
1479 /**
1480 * fpi_device_identify_complete:
1481 * @device: The #FpDevice
1482 * @error: (nullable) (transfer full): The #GError or %NULL on success
1483 *
1484 * Finish an ongoing identify operation.
1485 *
1486 * Note that @error should only be set for actual errors. In the case
1487 * of retry errors, report these using fpi_device_identify_report()
1488 * and then call this function without any error argument.
1489 *
1490 * If @error is not set, we expect that a match and / or a print have been
1491 * already reported via fpi_device_identify_report()
1492 */
1493 void
1494 80 fpi_device_identify_complete (FpDevice *device,
1495 GError *error)
1496 {
1497 80 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1498 80 FpMatchData *data;
1499
1500
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 80 times.
80 g_return_if_fail (FP_IS_DEVICE (device));
1501
2/2
✓ Branch 6 → 7 taken 79 times.
✓ Branch 6 → 9 taken 1 time.
80 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
1502
1503
1/2
✓ Branch 8 → 10 taken 79 times.
✗ Branch 8 → 13 not taken.
79 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1504 {
1505 158 g_autofree char *error_str = error_to_string (error);
1506
1507 79 g_debug ("Device reported identify completion (error: %s)", error_str);
1508 }
1509
1510 79 data = g_task_get_task_data (priv->current_task);
1511
1512 79 clear_device_cancel_action (device);
1513 79 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1514
1515
2/2
✓ Branch 16 → 17 taken 62 times.
✓ Branch 16 → 24 taken 17 times.
79 if (!error)
1516 {
1517
2/2
✓ Branch 17 → 18 taken 2 times.
✓ Branch 17 → 21 taken 60 times.
62 if (!data->result_reported)
1518 {
1519 2 g_warning ("Driver reported successful identify complete but did not report the result earlier. Reporting error instead");
1520 2 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1521 2 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1522 }
1523
2/2
✓ Branch 21 → 22 taken 10 times.
✓ Branch 21 → 23 taken 50 times.
60 else if (data->error)
1524 {
1525 10 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error));
1526 }
1527 else
1528 {
1529 50 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, GUINT_TO_POINTER (TRUE));
1530 }
1531 }
1532 else
1533 {
1534 /* Replace a retry error with a general error, this is a driver bug. */
1535
2/2
✓ Branch 25 → 26 taken 3 times.
✓ Branch 25 → 30 taken 14 times.
17 if (error->domain == FP_DEVICE_RETRY)
1536 {
1537 3 g_warning ("Driver reported a retry error to fpi_device_identify_complete. "
1538 "This is not permissible and needs to be reported using "
1539 "fpi_device_identify_report, reporting general identification "
1540 "failure instead.");
1541 3 g_clear_error (&error);
1542 3 error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL);
1543 }
1544 17 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1545 }
1546 }
1547
1548
1549 /**
1550 * fpi_device_capture_complete:
1551 * @device: The #FpDevice
1552 * @image: The #FpImage, or %NULL on error
1553 * @error: (nullable) (transfer full): The #GError or %NULL on success
1554 *
1555 * Finish an ongoing capture operation.
1556 */
1557 void
1558 22 fpi_device_capture_complete (FpDevice *device,
1559 FpImage *image,
1560 GError *error)
1561 {
1562 22 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1563
1564
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 22 times.
22 g_return_if_fail (FP_IS_DEVICE (device));
1565
2/2
✓ Branch 6 → 7 taken 21 times.
✓ Branch 6 → 9 taken 1 time.
22 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CAPTURE);
1566
1567
1/2
✓ Branch 8 → 10 taken 21 times.
✗ Branch 8 → 13 not taken.
21 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1568 {
1569 42 g_autofree char *error_str = error_to_string (error);
1570
1571 21 g_debug ("Device reported capture completion (image: %p, error: %s)",
1572 image, error_str);
1573 }
1574
1575 21 clear_device_cancel_action (device);
1576 21 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1577
1578
2/2
✓ Branch 15 → 16 taken 17 times.
✓ Branch 15 → 21 taken 4 times.
21 if (!error)
1579 {
1580
1/2
✓ Branch 16 → 17 taken 17 times.
✗ Branch 16 → 18 not taken.
17 if (image)
1581 {
1582 17 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_OBJECT, image);
1583 }
1584 else
1585 {
1586 g_warning ("Driver did not provide an error for a failed capture operation!");
1587 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1588 "Driver failed to provide an error!");
1589 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1590 }
1591 }
1592 else
1593 {
1594 4 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1595
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 25 taken 4 times.
4 if (image)
1596 {
1597 g_warning ("Driver passed an error but also provided an image, returning error!");
1598 g_clear_object (&image);
1599 }
1600 }
1601 }
1602
1603 /**
1604 * fpi_device_delete_complete:
1605 * @device: The #FpDevice
1606 * @error: (nullable) (transfer full): The #GError or %NULL on success
1607 *
1608 * Finish an ongoing delete operation.
1609 */
1610 void
1611 25 fpi_device_delete_complete (FpDevice *device,
1612 GError *error)
1613 {
1614 25 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1615
1616
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 25 times.
25 g_return_if_fail (FP_IS_DEVICE (device));
1617
2/2
✓ Branch 6 → 7 taken 24 times.
✓ Branch 6 → 9 taken 1 time.
25 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_DELETE);
1618
1619
1/2
✓ Branch 8 → 10 taken 24 times.
✗ Branch 8 → 13 not taken.
24 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1620 {
1621 48 g_autofree char *error_str = error_to_string (error);
1622
1623 24 g_debug ("Device reported delete completion (error: %s)", error_str);
1624 }
1625
1626 24 clear_device_cancel_action (device);
1627 24 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1628
1629
2/2
✓ Branch 15 → 16 taken 18 times.
✓ Branch 15 → 17 taken 6 times.
24 if (!error)
1630 18 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
1631 GUINT_TO_POINTER (TRUE));
1632 else
1633 6 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1634 }
1635
1636 /**
1637 * fpi_device_list_complete:
1638 * @device: The #FpDevice
1639 * @prints: (element-type FpPrint) (transfer container): Possibly empty array of prints or %NULL on error
1640 * @error: (nullable) (transfer full): The #GError or %NULL on success
1641 *
1642 * Finish an ongoing list operation.
1643 *
1644 * Please note that the @prints array will be free'ed using
1645 * g_ptr_array_unref() and the elements are destroyed automatically.
1646 * As such, you must use g_ptr_array_new_with_free_func() with
1647 * g_object_unref() as free func to create the array.
1648 */
1649 void
1650 53 fpi_device_list_complete (FpDevice *device,
1651 GPtrArray *prints,
1652 GError *error)
1653 {
1654 53 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1655
1656
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 53 times.
53 g_return_if_fail (FP_IS_DEVICE (device));
1657
2/2
✓ Branch 6 → 7 taken 52 times.
✓ Branch 6 → 9 taken 1 time.
53 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_LIST);
1658
1659
1/2
✓ Branch 8 → 10 taken 52 times.
✗ Branch 8 → 15 not taken.
52 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1660 {
1661 104 g_autofree char *error_str = error_to_string (error);
1662
1663
2/2
✓ Branch 11 → 12 taken 48 times.
✓ Branch 11 → 13 taken 4 times.
52 g_debug ("Device reported listing completion (prints: %ld, error: %s)",
1664 prints ? (long) prints->len : -1, error_str);
1665 }
1666
1667 52 clear_device_cancel_action (device);
1668 52 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
1669
1670
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 52 times.
52 if (prints && error)
1671 {
1672 g_warning ("Driver reported back prints and error, ignoring prints");
1673 g_clear_pointer (&prints, g_ptr_array_unref);
1674 }
1675
3/4
✓ Branch 20 → 21 taken 4 times.
✓ Branch 20 → 24 taken 48 times.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 26 taken 4 times.
52 else if (!prints && !error)
1676 {
1677 g_warning ("Driver did not pass array but failed to provide an error");
1678 error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
1679 "Driver failed to provide a list of prints");
1680 }
1681
1682
1/2
✓ Branch 24 → 25 taken 48 times.
✗ Branch 24 → 26 not taken.
48 if (!error)
1683 48 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_PTR_ARRAY, prints);
1684 else
1685 4 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
1686 }
1687
1688 static int
1689 62 update_attr (const char *attr, const char *value)
1690 {
1691 62 int fd, err;
1692 62 gssize r;
1693 62 char buf[50] = { 0 };
1694
1695 62 fd = open (attr, O_RDONLY);
1696 62 err = -errno;
1697
2/2
✓ Branch 3 → 4 taken 56 times.
✓ Branch 3 → 19 taken 6 times.
62 if (fd < 0)
1698 return -err;
1699
1700 56 r = read (fd, buf, sizeof (buf) - 1);
1701 56 err = errno;
1702 56 close (fd);
1703
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 56 times.
56 if (r < 0)
1704 return -err;
1705
1706 56 g_strchomp (buf);
1707
2/2
✓ Branch 10 → 11 taken 17 times.
✓ Branch 10 → 19 taken 39 times.
56 if (g_strcmp0 (buf, value) == 0)
1708 return 0;
1709
1710 /* O_TRUNC makes things work in the umockdev environment */
1711 17 fd = open (attr, O_WRONLY | O_TRUNC);
1712 17 err = errno;
1713
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 17 times.
17 if (fd < 0)
1714 return -err;
1715
1716 17 r = write (fd, value, strlen (value));
1717 17 err = -errno;
1718 17 close (fd);
1719
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 17 times.
17 if (r < 0)
1720 {
1721 /* Write failures are weird, and are worth a warning */
1722 g_warning ("Could not write %s to %s", value, attr);
1723 return -err;
1724 }
1725
1726 return 0;
1727 }
1728
1729 static void
1730 complete_suspend_resume_task (FpDevice *device)
1731 {
1732 g_autoptr(GTask) task = NULL;
1733 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1734
1735 g_assert (priv->suspend_resume_task);
1736 task = g_steal_pointer (&priv->suspend_resume_task);
1737
1738 g_task_return_boolean (task, TRUE);
1739 }
1740
1741 void
1742 9 fpi_device_suspend (FpDevice *device)
1743 {
1744 9 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1745
1746 /* If the device is currently idle, just complete immediately.
1747 * For long running tasks, call the driver handler right away, for short
1748 * tasks, wait for completion and then return the task.
1749 */
1750
2/3
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 6 taken 7 times.
✗ Branch 3 → 12 not taken.
9 switch (priv->current_action)
1751 {
1752 2 case FPI_DEVICE_ACTION_NONE:
1753 2 fpi_device_suspend_complete (device, NULL);
1754 2 break;
1755
1756 case FPI_DEVICE_ACTION_ENROLL:
1757 case FPI_DEVICE_ACTION_VERIFY:
1758 case FPI_DEVICE_ACTION_IDENTIFY:
1759 case FPI_DEVICE_ACTION_CAPTURE:
1760
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 10 not taken.
7 if (FP_DEVICE_GET_CLASS (device)->suspend)
1761 {
1762
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 5 times.
7 if (priv->critical_section)
1763 2 priv->suspend_queued = TRUE;
1764 else
1765 5 FP_DEVICE_GET_CLASS (device)->suspend (device);
1766 }
1767 else
1768 {
1769 fpi_device_suspend_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
1770 }
1771 break;
1772
1773 default:
1774 case FPI_DEVICE_ACTION_PROBE:
1775 case FPI_DEVICE_ACTION_OPEN:
1776 case FPI_DEVICE_ACTION_CLOSE:
1777 case FPI_DEVICE_ACTION_DELETE:
1778 case FPI_DEVICE_ACTION_LIST:
1779 case FPI_DEVICE_ACTION_CLEAR_STORAGE:
1780 g_signal_connect_object (priv->current_task,
1781 "notify::completed",
1782 G_CALLBACK (complete_suspend_resume_task),
1783 device,
1784 G_CONNECT_SWAPPED);
1785
1786 break;
1787 }
1788 9 }
1789
1790 void
1791 8 fpi_device_resume (FpDevice *device)
1792 {
1793 8 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1794
1795
2/3
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 4 times.
✗ Branch 3 → 11 not taken.
8 switch (priv->current_action)
1796 {
1797 4 case FPI_DEVICE_ACTION_NONE:
1798 4 fpi_device_resume_complete (device, NULL);
1799 4 break;
1800
1801 case FPI_DEVICE_ACTION_ENROLL:
1802 case FPI_DEVICE_ACTION_VERIFY:
1803 case FPI_DEVICE_ACTION_IDENTIFY:
1804 case FPI_DEVICE_ACTION_CAPTURE:
1805
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 9 not taken.
4 if (FP_DEVICE_GET_CLASS (device)->resume)
1806 {
1807
2/2
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 3 times.
4 if (priv->critical_section)
1808 1 priv->resume_queued = TRUE;
1809 else
1810 3 FP_DEVICE_GET_CLASS (device)->resume (device);
1811 }
1812 else
1813 {
1814 fpi_device_resume_complete (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
1815 }
1816 break;
1817
1818 default:
1819 case FPI_DEVICE_ACTION_PROBE:
1820 case FPI_DEVICE_ACTION_OPEN:
1821 case FPI_DEVICE_ACTION_CLOSE:
1822 case FPI_DEVICE_ACTION_DELETE:
1823 case FPI_DEVICE_ACTION_LIST:
1824 case FPI_DEVICE_ACTION_CLEAR_STORAGE:
1825 /* cannot happen as we make sure these tasks complete before suspend */
1826 g_assert_not_reached ();
1827 complete_suspend_resume_task (device);
1828 break;
1829 }
1830 8 }
1831
1832 void
1833 160 fpi_device_configure_wakeup (FpDevice *device, gboolean enabled)
1834 {
1835 160 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1836
1837
2/3
✓ Branch 3 → 4 taken 31 times.
✗ Branch 3 → 34 not taken.
✓ Branch 3 → 35 taken 129 times.
160 switch (priv->type)
1838 {
1839 31 case FP_DEVICE_TYPE_USB:
1840 {
1841 62 g_autoptr(GString) ports = NULL;
1842 31 g_autoptr(GUsbDevice) dev = NULL;
1843
2/2
✓ Branch 4 → 5 taken 30 times.
✓ Branch 4 → 6 taken 1 time.
31 const char *wakeup_command = enabled ? "enabled" : "disabled";
1844 31 guint8 bus;
1845
1/2
✓ Branch 30 → 31 taken 31 times.
✗ Branch 30 → 32 not taken.
31 g_autofree gchar *sysfs_wakeup = NULL;
1846 31 g_autofree gchar *sysfs_persist = NULL;
1847 31 int res;
1848
1849 31 ports = g_string_new (NULL);
1850 31 bus = g_usb_device_get_bus (priv->usb_device);
1851
1852 /* Walk up, skipping the root hub. */
1853 31 g_set_object (&dev, priv->usb_device);
1854 107 while (TRUE)
1855 38 {
1856 107 g_autoptr(GUsbDevice) parent = g_usb_device_get_parent (dev);
1857 69 g_autofree gchar *port_str = NULL;
1858 69 guint8 port;
1859
1860
2/2
✓ Branch 10 → 11 taken 38 times.
✓ Branch 10 → 18 taken 31 times.
69 if (!parent)
1861 break;
1862
1863 38 port = g_usb_device_get_port_number (dev);
1864 38 port_str = g_strdup_printf ("%d.", port);
1865 38 g_string_prepend (ports, port_str);
1866 38 g_set_object (&dev, parent);
1867 }
1868 31 g_string_set_size (ports, ports->len - 1);
1869
1870 31 sysfs_wakeup = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/wakeup", bus, ports->str);
1871 31 res = update_attr (sysfs_wakeup, wakeup_command);
1872
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 24 taken 31 times.
31 if (res < 0)
1873 g_debug ("Failed to set %s to %s", sysfs_wakeup, wakeup_command);
1874
1875 /* Persist means that the kernel tries to keep the USB device open
1876 * in case it is "replugged" due to suspend.
1877 * This is not helpful, as it will receive a reset and will be in a bad
1878 * state. Instead, seeing an unplug and a new device makes more sense.
1879 */
1880 31 sysfs_persist = g_strdup_printf ("/sys/bus/usb/devices/%d-%s/power/persist", bus, ports->str);
1881 31 res = update_attr (sysfs_persist, "0");
1882
1/2
✗ Branch 26 → 27 not taken.
✓ Branch 26 → 28 taken 31 times.
31 if (res < 0)
1883 g_warning ("Failed to disable USB persist by writing to %s", sysfs_persist);
1884
1885 31 break;
1886 }
1887
1888 case FP_DEVICE_TYPE_VIRTUAL:
1889 case FP_DEVICE_TYPE_UDEV:
1890 break;
1891
1892 default:
1893 g_assert_not_reached ();
1894 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
1895 fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
1896 return;
1897 }
1898 }
1899
1900 static void
1901 7 fpi_device_suspend_completed (FpDevice *device)
1902 {
1903 14 g_autoptr(GTask) task = NULL;
1904 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1905
1906 /* We have an ongoing operation, allow the device to wake up the machine. */
1907
2/2
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 4 times.
7 if (priv->current_action != FPI_DEVICE_ACTION_NONE)
1908 3 fpi_device_configure_wakeup (device, TRUE);
1909
1910
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 7 times.
7 if (priv->critical_section)
1911 g_warning ("Driver was in a critical section at suspend time. It likely deadlocked!");
1912
1913
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 5 times.
7 task = g_steal_pointer (&priv->suspend_resume_task);
1914
1915
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 9 taken 5 times.
7 if (priv->suspend_error)
1916 2 g_task_return_error (task, g_steal_pointer (&priv->suspend_error));
1917 else
1918 5 g_task_return_boolean (task, TRUE);
1919 7 }
1920
1921 /**
1922 * fpi_device_suspend_complete:
1923 * @device: The #FpDevice
1924 * @error: (nullable) (transfer full): The #GError or %NULL on success
1925 *
1926 * Finish a suspend request. Only return a %NULL error if suspend has been
1927 * correctly configured and the current action as returned by
1928 * fpi_device_get_current_action() will continue to run after resume.
1929 *
1930 * In all other cases an error must be returned. Should this happen, the
1931 * current action will be cancelled before the error is forwarded to the
1932 * application.
1933 *
1934 * It is recommended to set @error to #FP_DEVICE_ERROR_NOT_SUPPORTED.
1935 */
1936 void
1937 7 fpi_device_suspend_complete (FpDevice *device,
1938 GError *error)
1939 {
1940 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1941
1942
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
7 g_return_if_fail (FP_IS_DEVICE (device));
1943
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 8 not taken.
7 g_return_if_fail (priv->suspend_resume_task);
1944
1/2
✓ Branch 7 → 9 taken 7 times.
✗ Branch 7 → 11 not taken.
7 g_return_if_fail (priv->suspend_error == NULL);
1945
1946
1/2
✓ Branch 10 → 12 taken 7 times.
✗ Branch 10 → 15 not taken.
7 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1947 {
1948 14 g_autofree char *error_str = error_to_string (error);
1949
1950 7 g_debug ("Device reported suspend completion (error: %s)", error_str);
1951 }
1952
1953
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 5 times.
7 priv->suspend_error = g_steal_pointer (&error);
1954 7 priv->is_suspended = TRUE;
1955
1956 /* If there is no error, we have no running task, return immediately. */
1957
4/6
✓ Branch 15 → 16 taken 2 times.
✓ Branch 15 → 19 taken 5 times.
✓ Branch 16 → 17 taken 2 times.
✗ Branch 16 → 19 not taken.
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 21 taken 2 times.
9 if (!priv->suspend_error || !priv->current_task ||
1958 2 g_task_get_completed (priv->current_task))
1959 {
1960 5 fpi_device_suspend_completed (device);
1961 5 return;
1962 }
1963
1964 /* Wait for completion of the current task. */
1965 2 g_signal_connect_object (priv->current_task,
1966 "notify::completed",
1967 G_CALLBACK (fpi_device_suspend_completed),
1968 device,
1969 G_CONNECT_SWAPPED);
1970
1971 /* And cancel any action that might be long-running. */
1972
1/2
✓ Branch 22 → 23 taken 2 times.
✗ Branch 22 → 25 not taken.
2 if (!priv->current_cancellation_reason)
1973 2 priv->current_cancellation_reason = fpi_device_error_new_msg (FP_DEVICE_ERROR_BUSY,
1974 "Cannot run while suspended.");
1975
1976 2 g_cancellable_cancel (priv->current_cancellable);
1977 }
1978
1979 /**
1980 * fpi_device_resume_complete:
1981 * @device: The #FpDevice
1982 * @error: (nullable) (transfer full): The #GError or %NULL on success
1983 *
1984 * Finish a resume request.
1985 */
1986 void
1987 7 fpi_device_resume_complete (FpDevice *device,
1988 GError *error)
1989 {
1990 14 g_autoptr(GTask) task = NULL;
1991 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1992
1993
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7 times.
7 g_return_if_fail (FP_IS_DEVICE (device));
1994
1/2
✓ Branch 6 → 7 taken 7 times.
✗ Branch 6 → 9 not taken.
7 g_return_if_fail (priv->suspend_resume_task);
1995
1996
1/2
✓ Branch 8 → 10 taken 7 times.
✗ Branch 8 → 13 not taken.
7 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
1997 {
1998 14 g_autofree char *error_str = error_to_string (error);
1999
2000 7 g_debug ("Device reported resume completion (error: %s)", error_str);
2001 }
2002
2003 7 priv->is_suspended = FALSE;
2004 7 fpi_device_configure_wakeup (device, FALSE);
2005
2006
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 7 times.
7 task = g_steal_pointer (&priv->suspend_resume_task);
2007
2008
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 16 taken 7 times.
7 if (error)
2009 g_task_return_error (task, error);
2010 else
2011 7 g_task_return_boolean (task, TRUE);
2012 }
2013
2014 /**
2015 * fpi_device_clear_storage_complete:
2016 * @device: The #FpDevice
2017 * @error: (nullable) (transfer full): The #GError or %NULL on success
2018 *
2019 * Finish an ongoing clear_storage operation.
2020 */
2021 void
2022 61 fpi_device_clear_storage_complete (FpDevice *device,
2023 GError *error)
2024 {
2025 61 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2026
2027
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 61 times.
61 g_return_if_fail (FP_IS_DEVICE (device));
2028
1/2
✓ Branch 6 → 7 taken 61 times.
✗ Branch 6 → 9 not taken.
61 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_CLEAR_STORAGE);
2029
2030
1/2
✓ Branch 8 → 10 taken 61 times.
✗ Branch 8 → 13 not taken.
61 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2031 {
2032 122 g_autofree char *error_str = error_to_string (error);
2033
2034 61 g_debug ("Device reported clear storage completion (error: %s)", error_str);
2035 }
2036
2037 61 clear_device_cancel_action (device);
2038 61 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
2039
2040
2/2
✓ Branch 15 → 16 taken 57 times.
✓ Branch 15 → 17 taken 4 times.
61 if (!error)
2041 57 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
2042 GUINT_TO_POINTER (TRUE));
2043 else
2044 4 fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
2045 }
2046
2047 /**
2048
2049 * fpi_device_enroll_progress:
2050 * @device: The #FpDevice
2051 * @completed_stages: The number of stages that are completed at this point
2052 * @print: (transfer floating): The #FpPrint for the newly completed stage or %NULL on failure
2053 * @error: (nullable) (transfer full): The #GError or %NULL on success
2054 *
2055 * Notify about the progress of the enroll operation. This is important for UI interaction.
2056 * The passed error may be used if a scan needs to be retried, use fpi_device_retry_new().
2057 */
2058 void
2059 476 fpi_device_enroll_progress (FpDevice *device,
2060 gint completed_stages,
2061 FpPrint *print,
2062 GError *error)
2063 {
2064 476 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2065 476 FpEnrollData *data;
2066
2067
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 476 times.
476 g_return_if_fail (FP_IS_DEVICE (device));
2068
2/2
✓ Branch 6 → 7 taken 475 times.
✓ Branch 6 → 8 taken 1 time.
476 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_ENROLL);
2069
4/4
✓ Branch 7 → 9 taken 71 times.
✓ Branch 7 → 11 taken 404 times.
✓ Branch 10 → 11 taken 70 times.
✓ Branch 10 → 13 taken 1 time.
475 g_return_if_fail (error == NULL || error->domain == FP_DEVICE_RETRY);
2070
2071 474 g_debug ("Device reported enroll progress, reported %i of %i have been completed", completed_stages, priv->nr_enroll_stages);
2072
2073
2/2
✓ Branch 12 → 14 taken 308 times.
✓ Branch 12 → 15 taken 166 times.
474 if (print)
2074 308 g_object_ref_sink (print);
2075
2076
2/2
✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 18 taken 473 times.
474 if (error && print)
2077 {
2078 1 g_warning ("Driver passed an error and also provided a print, returning error!");
2079 1 g_clear_object (&print);
2080 }
2081
2082 474 data = g_task_get_task_data (priv->current_task);
2083
2084
2/2
✓ Branch 19 → 20 taken 418 times.
✓ Branch 19 → 21 taken 56 times.
474 if (data->enroll_progress_cb)
2085 {
2086 418 data->enroll_progress_cb (device,
2087 completed_stages,
2088 print,
2089 data->enroll_progress_data,
2090 error);
2091 }
2092
2093 474 g_clear_error (&error);
2094
2/2
✓ Branch 22 → 23 taken 307 times.
✓ Branch 22 → 24 taken 167 times.
474 g_clear_object (&print);
2095 }
2096
2097 /**
2098 * fpi_device_verify_report:
2099 * @device: The #FpDevice
2100 * @result: The #FpiMatchResult of the operation
2101 * @print: (transfer floating) The scanned #FpPrint
2102 * @error: A #GError if result is %FPI_MATCH_ERROR
2103 *
2104 * Report the result of a verify operation. Note that the passed @error must be
2105 * a retry error with the %FP_DEVICE_RETRY domain. For all other error cases,
2106 * the error should passed to fpi_device_verify_complete().
2107 */
2108 void
2109 28 fpi_device_verify_report (FpDevice *device,
2110 FpiMatchResult result,
2111 FpPrint *print,
2112 GError *error)
2113 {
2114 28 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2115 28 FpMatchData *data = g_task_get_task_data (priv->current_task);
2116 28 gboolean call_cb = TRUE;
2117
2118
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 28 times.
28 g_return_if_fail (FP_IS_DEVICE (device));
2119
1/2
✓ Branch 7 → 8 taken 28 times.
✗ Branch 7 → 9 not taken.
28 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
2120
1/2
✓ Branch 8 → 10 taken 28 times.
✗ Branch 8 → 12 not taken.
28 g_return_if_fail (data->result_reported == FALSE);
2121
2122 28 data->result_reported = TRUE;
2123
2124
1/2
✓ Branch 11 → 13 taken 28 times.
✗ Branch 11 → 19 not taken.
28 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2125 {
2126 56 g_autofree char *result_str = g_enum_to_string (FPI_TYPE_MATCH_RESULT, result);
2127 56 g_autofree char *error_str = error_to_string (error);
2128
2129 28 g_debug ("Device reported verify result (result: %s, print: %p, error: %s)",
2130 result_str, print, error_str);
2131 }
2132
2133
2/2
✓ Branch 19 → 20 taken 13 times.
✓ Branch 19 → 21 taken 15 times.
28 if (print)
2134 13 print = g_object_ref_sink (print);
2135
2136
2/2
✓ Branch 21 → 22 taken 13 times.
✓ Branch 21 → 33 taken 15 times.
28 if (error || result == FPI_MATCH_ERROR)
2137 {
2138
2/2
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 24 taken 11 times.
13 if (result != FPI_MATCH_ERROR)
2139 2 g_warning ("Driver reported an error code without setting match result to error!");
2140
2141
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 27 taken 12 times.
13 if (error == NULL)
2142 {
2143 1 g_warning ("Driver reported an error without specifying a retry code, assuming general retry error!");
2144 1 error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
2145 }
2146
2147
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 30 taken 12 times.
13 if (print)
2148 {
2149 1 g_warning ("Driver reported a print together with an error!");
2150 1 g_clear_object (&print);
2151 }
2152
2153 13 data->error = error;
2154
2155
2/2
✓ Branch 31 → 32 taken 1 time.
✓ Branch 31 → 44 taken 12 times.
13 if (error->domain != FP_DEVICE_RETRY)
2156 {
2157 1 g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!");
2158 1 call_cb = FALSE;
2159 }
2160 }
2161 else
2162 {
2163
2/2
✓ Branch 33 → 34 taken 8 times.
✓ Branch 33 → 43 taken 7 times.
15 if (result == FPI_MATCH_SUCCESS)
2164 {
2165 8 fpi_device_get_verify_data (device, &data->match);
2166 8 g_object_ref (data->match);
2167
2168
3/4
✓ Branch 36 → 37 taken 7 times.
✓ Branch 36 → 43 taken 1 time.
✓ Branch 38 → 39 taken 7 times.
✗ Branch 38 → 43 not taken.
15 if (print &&
2169
2/2
✓ Branch 40 → 41 taken 1 time.
✓ Branch 40 → 43 taken 6 times.
14 fpi_print_get_type (print) != FPI_PRINT_NBIS &&
2170 7 !fp_print_equal (print, data->match))
2171 {
2172 1 g_warning ("Driver reported a match providing a scanned print that is not matching it.");
2173 1 g_clear_object (&print);
2174 }
2175 }
2176
2177 15 data->print = g_steal_pointer (&print);
2178 }
2179
2180
2/2
✓ Branch 44 → 45 taken 15 times.
✓ Branch 44 → 46 taken 12 times.
28 if (call_cb && data->match_cb)
2181 15 data->match_cb (device, data->match, data->print, data->match_data, data->error);
2182 }
2183
2184 /**
2185 * fpi_device_identify_report:
2186 * @device: The #FpDevice
2187 * @match: (transfer none): The #FpPrint from the gallery that matched
2188 * @print: (transfer floating): The scanned #FpPrint, set in the absence
2189 * of an error.
2190 * @error: A #GError of %FP_DEVICE_RETRY type if @match and @print are unset.
2191 *
2192 * Report the results of an identify operation.
2193 *
2194 * In case of successful identification @match is expected to be set to a
2195 * #FpPrint that matches one from the provided gallery, while @print
2196 * represents the scanned print and will be different.
2197 *
2198 * If there are no errors, it's expected that the device always reports the
2199 * recognized @print even if there is no @match with the provided gallery (that
2200 * can be potentially empty). This is required for application logic further
2201 * up in the stack, such as for enroll-duplicate checking. @print needs to be
2202 * sufficiently filled to do a comparison.
2203 *
2204 * In case of error, both @match and @print are expected to be %NULL.
2205 * Note that the passed @error must be a retry error from the %FP_DEVICE_RETRY
2206 * domain. For all other error cases, the error should passed to
2207 * fpi_device_identify_complete().
2208 */
2209 void
2210 64 fpi_device_identify_report (FpDevice *device,
2211 FpPrint *match,
2212 FpPrint *print,
2213 GError *error)
2214 {
2215 64 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2216 64 FpMatchData *data = g_task_get_task_data (priv->current_task);
2217 64 gboolean call_cb = TRUE;
2218
2219
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 64 times.
64 g_return_if_fail (FP_IS_DEVICE (device));
2220
1/2
✓ Branch 7 → 8 taken 64 times.
✗ Branch 7 → 9 not taken.
64 g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
2221
1/2
✓ Branch 8 → 10 taken 64 times.
✗ Branch 8 → 11 not taken.
64 g_return_if_fail (data->result_reported == FALSE);
2222
2223 64 data->result_reported = TRUE;
2224
2225
2/2
✓ Branch 10 → 12 taken 41 times.
✓ Branch 10 → 13 taken 23 times.
64 if (match)
2226 41 g_object_ref (match);
2227
2228
2/2
✓ Branch 13 → 14 taken 47 times.
✓ Branch 13 → 15 taken 17 times.
64 if (print)
2229 47 print = g_object_ref_sink (print);
2230
2231
1/2
✓ Branch 16 → 17 taken 64 times.
✗ Branch 16 → 20 not taken.
64 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2232 {
2233 128 g_autofree char *error_str = error_to_string (error);
2234
2235 64 g_debug ("Device reported identify result (match: %p, print: %p, error: %s)",
2236 match, print, error_str);
2237 }
2238
2239
4/4
✓ Branch 20 → 21 taken 41 times.
✓ Branch 20 → 25 taken 23 times.
✓ Branch 22 → 23 taken 2 times.
✓ Branch 22 → 25 taken 39 times.
64 if (match && !g_ptr_array_find (data->gallery, match, NULL))
2240 {
2241 2 g_warning ("Driver reported a match to a print that was not in the gallery, ignoring match.");
2242 2 g_clear_object (&match);
2243 }
2244
2245
2/2
✓ Branch 25 → 26 taken 14 times.
✓ Branch 25 → 35 taken 50 times.
64 if (error)
2246 {
2247
2/2
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 29 taken 13 times.
14 if (match != NULL)
2248 {
2249 1 g_warning ("Driver reported an error code but also provided a match!");
2250 1 g_clear_object (&match);
2251 }
2252
2253
2/2
✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 32 taken 12 times.
14 if (print)
2254 {
2255 2 g_warning ("Driver reported a print together with an error!");
2256 2 g_clear_object (&print);
2257 }
2258
2259 14 data->error = error;
2260
2261
2/2
✓ Branch 33 → 34 taken 2 times.
✓ Branch 33 → 46 taken 12 times.
14 if (error->domain != FP_DEVICE_RETRY)
2262 {
2263 2 g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!");
2264 2 call_cb = FALSE;
2265 }
2266 }
2267 else
2268 {
2269
7/8
✓ Branch 35 → 36 taken 38 times.
✓ Branch 35 → 44 taken 12 times.
✓ Branch 36 → 37 taken 38 times.
✗ Branch 36 → 43 not taken.
✓ Branch 38 → 39 taken 32 times.
✓ Branch 38 → 43 taken 6 times.
✓ Branch 40 → 41 taken 1 time.
✓ Branch 40 → 43 taken 31 times.
82 if (match && print && fpi_print_get_type (print) != FPI_PRINT_NBIS &&
2270 32 !g_ptr_array_find_with_equal_func (data->gallery, print,
2271 (GEqualFunc) fp_print_equal, NULL))
2272 {
2273 1 g_warning ("Driver reported a match providing a scanned print that is not matching any in the gallery.");
2274 1 g_clear_object (&print);
2275 }
2276
2277 38 if (match)
2278 38 data->match = g_steal_pointer (&match);
2279
2280
2/2
✓ Branch 44 → 45 taken 44 times.
✓ Branch 44 → 46 taken 6 times.
50 if (print)
2281 44 data->print = g_steal_pointer (&print);
2282 }
2283
2284
2/2
✓ Branch 46 → 47 taken 28 times.
✓ Branch 46 → 48 taken 34 times.
64 if (call_cb && data->match_cb)
2285 28 data->match_cb (device, data->match, data->print, data->match_data, data->error);
2286 }
2287
2288 /**
2289 * fpi_device_report_finger_status:
2290 * @device: The #FpDevice
2291 * @finger_status: The current #FpFingerStatusFlags to report
2292 *
2293 * Report the finger status for the @device.
2294 * This can be used by UI to give a feedback
2295 *
2296 * Returns: %TRUE if changed
2297 */
2298 gboolean
2299 2995 fpi_device_report_finger_status (FpDevice *device,
2300 FpFingerStatusFlags finger_status)
2301 {
2302 2995 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2303
2304
2/2
✓ Branch 3 → 4 taken 1241 times.
✓ Branch 3 → 15 taken 1754 times.
2995 if (priv->finger_status == finger_status)
2305 return FALSE;
2306
2307
1/2
✓ Branch 5 → 6 taken 1241 times.
✗ Branch 5 → 13 not taken.
1241 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2308 {
2309 1241 g_autofree char *status_string = NULL;
2310 1241 g_autofree char *old_status_string = NULL;
2311
2312 1241 old_status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, priv->finger_status);
2313 1241 status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status);
2314
2315 1241 g_debug ("Device reported finger status change: %s -> %s",
2316 old_status_string, status_string);
2317 }
2318
2319 1241 priv->finger_status = finger_status;
2320 1241 g_object_notify (G_OBJECT (device), "finger-status");
2321
2322 1241 return TRUE;
2323 }
2324
2325 /**
2326 * fpi_device_report_finger_status_changes:
2327 * @device: The #FpDevice
2328 * @added_status: The #FpFingerStatusFlags to add
2329 * @removed_status: The #FpFingerStatusFlags to remove
2330 *
2331 * Report the finger status for the @device adding the @added_status flags
2332 * and removing the @removed_status flags.
2333 *
2334 * This can be used by UI to give a feedback
2335 *
2336 * Returns: %TRUE if changed
2337 */
2338 gboolean
2339 1418 fpi_device_report_finger_status_changes (FpDevice *device,
2340 FpFingerStatusFlags added_status,
2341 FpFingerStatusFlags removed_status)
2342 {
2343 1418 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2344 1418 FpFingerStatusFlags finger_status = priv->finger_status;
2345
2346 1418 finger_status |= added_status;
2347 1418 finger_status &= ~removed_status;
2348
2349 1418 return fpi_device_report_finger_status (device, finger_status);
2350 }
2351
2352 static void
2353 35 update_temp_timeout (FpDevice *device, gpointer user_data)
2354 {
2355 35 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2356
2357 35 fpi_device_update_temp (device, priv->temp_last_active);
2358 35 }
2359
2360 /**
2361 * fpi_device_update_temp:
2362 * @device: The #FpDevice
2363 * @is_active: Whether the device is now active
2364 *
2365 * Purely internal function to update the temperature. Also ensure that the
2366 * state is updated once a threshold is reached.
2367 */
2368 void
2369 1167 fpi_device_update_temp (FpDevice *device, gboolean is_active)
2370 {
2371 1167 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2372 1167 gint64 now = g_get_monotonic_time ();
2373 1167 gdouble passed_seconds;
2374 1167 gdouble alpha;
2375 1167 gdouble next_threshold;
2376 1167 gdouble old_ratio;
2377 1167 FpTemperature old_temp;
2378
2379
2/2
✓ Branch 4 → 5 taken 118 times.
✓ Branch 4 → 7 taken 1049 times.
1167 if (priv->temp_hot_seconds < 0)
2380 {
2381 118 g_debug ("Not updating temperature model, device can run continuously!");
2382 118 return;
2383 }
2384
2385 1049 passed_seconds = (now - priv->temp_last_update) / 1e6;
2386 1049 old_ratio = priv->temp_current_ratio;
2387
2388
2/2
✓ Branch 7 → 8 taken 207 times.
✓ Branch 7 → 9 taken 842 times.
1049 if (priv->temp_last_active)
2389 {
2390 207 alpha = exp (-passed_seconds / priv->temp_hot_seconds);
2391 207 priv->temp_current_ratio = alpha * priv->temp_current_ratio + 1 - alpha;
2392 }
2393 else
2394 {
2395 842 alpha = exp (-passed_seconds / priv->temp_cold_seconds);
2396 842 priv->temp_current_ratio = alpha * priv->temp_current_ratio;
2397 }
2398
2399 1049 priv->temp_last_active = is_active;
2400 1049 priv->temp_last_update = now;
2401
2402 1049 old_temp = priv->temp_current;
2403
2/2
✓ Branch 10 → 11 taken 663 times.
✓ Branch 10 → 12 taken 386 times.
1049 if (priv->temp_current_ratio < TEMP_COLD_THRESH)
2404 {
2405 663 priv->temp_current = FP_TEMPERATURE_COLD;
2406
2/2
✓ Branch 11 → 20 taken 109 times.
✓ Branch 11 → 21 taken 554 times.
663 next_threshold = is_active ? TEMP_COLD_THRESH : -1.0;
2407 }
2408
2/2
✓ Branch 12 → 13 taken 382 times.
✓ Branch 12 → 14 taken 4 times.
386 else if (priv->temp_current_ratio < TEMP_HOT_WARM_THRESH)
2409 {
2410 382 priv->temp_current = FP_TEMPERATURE_WARM;
2411
2/2
✓ Branch 13 → 20 taken 286 times.
✓ Branch 13 → 21 taken 96 times.
491 next_threshold = is_active ? TEMP_WARM_HOT_THRESH : TEMP_COLD_THRESH;
2412 }
2413
1/2
✗ Branch 14 → 15 not taken.
✓ Branch 14 → 19 taken 4 times.
4 else if (priv->temp_current_ratio < TEMP_WARM_HOT_THRESH)
2414 {
2415 /* Keep HOT until we reach TEMP_HOT_WARM_THRESH */
2416 if (priv->temp_current != FP_TEMPERATURE_HOT)
2417 priv->temp_current = FP_TEMPERATURE_WARM;
2418
2419 next_threshold = is_active ? TEMP_WARM_HOT_THRESH : TEMP_HOT_WARM_THRESH;
2420 }
2421 else
2422 {
2423 4 priv->temp_current = FP_TEMPERATURE_HOT;
2424
2/2
✓ Branch 19 → 18 taken 2 times.
✓ Branch 19 → 21 taken 2 times.
4 next_threshold = is_active ? -1.0 : TEMP_HOT_WARM_THRESH;
2425 }
2426
2427
1/2
✓ Branch 22 → 23 taken 1049 times.
✗ Branch 22 → 30 not taken.
1049 if (!g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, G_LOG_DOMAIN))
2428 {
2429 2098 g_autofree char *old_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, old_temp);
2430 2098 g_autofree char *new_temp_str = g_enum_to_string (FP_TYPE_TEMPERATURE, priv->temp_current);
2431
2432 1049 g_debug ("Updated temperature model after %0.2f seconds, ratio %0.2f -> %0.2f, active %d -> %d, %s -> %s",
2433 passed_seconds,
2434 old_ratio,
2435 priv->temp_current_ratio,
2436 priv->temp_last_active,
2437 is_active,
2438 old_temp_str,
2439 new_temp_str);
2440 }
2441
2442
2/2
✓ Branch 30 → 31 taken 97 times.
✓ Branch 30 → 32 taken 952 times.
1049 if (priv->temp_current != old_temp)
2443 97 g_object_notify (G_OBJECT (device), "temperature");
2444
2445 /* If the device is HOT, then do an internal cancellation of long running tasks. */
2446
2/2
✓ Branch 32 → 33 taken 4 times.
✓ Branch 32 → 38 taken 1045 times.
1049 if (priv->temp_current == FP_TEMPERATURE_HOT)
2447 {
2448 4 if (priv->current_action == FPI_DEVICE_ACTION_ENROLL ||
2449 priv->current_action == FPI_DEVICE_ACTION_VERIFY ||
2450
2/2
✓ Branch 33 → 34 taken 1 time.
✓ Branch 33 → 38 taken 3 times.
4 priv->current_action == FPI_DEVICE_ACTION_IDENTIFY ||
2451 priv->current_action == FPI_DEVICE_ACTION_CAPTURE)
2452 {
2453
1/2
✓ Branch 34 → 35 taken 1 time.
✗ Branch 34 → 37 not taken.
1 if (!priv->current_cancellation_reason)
2454 1 priv->current_cancellation_reason = fpi_device_error_new (FP_DEVICE_ERROR_TOO_HOT);
2455
2456 1 g_cancellable_cancel (priv->current_cancellable);
2457 }
2458 }
2459
2460
2/2
✓ Branch 38 → 39 taken 410 times.
✓ Branch 38 → 40 taken 639 times.
1049 g_clear_pointer (&priv->temp_timeout, g_source_destroy);
2461
2462
2/2
✓ Branch 40 → 41 taken 493 times.
✓ Branch 40 → 46 taken 556 times.
1049 if (next_threshold < 0)
2463 return;
2464
2465 /* Set passed_seconds to the time until the next update is needed */
2466
2/2
✓ Branch 41 → 42 taken 205 times.
✓ Branch 41 → 43 taken 288 times.
493 if (is_active)
2467 205 passed_seconds = -priv->temp_hot_seconds * log ((next_threshold - 1.0) / (priv->temp_current_ratio - 1.0));
2468 else
2469 288 passed_seconds = -priv->temp_cold_seconds * log (next_threshold / priv->temp_current_ratio);
2470
2471 493 passed_seconds += TEMP_DELAY_SECONDS;
2472
2473 493 priv->temp_timeout = fpi_device_add_timeout (device,
2474 493 passed_seconds * 1000,
2475 update_temp_timeout,
2476 NULL, NULL);
2477 }
2478