GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/virtual-device.c
Date: 2024-05-04 14:54:39
Exec Total Coverage
Lines: 337 364 92.6%
Functions: 21 22 95.5%
Branches: 208 294 70.7%

Line Branch Exec Source
1 /*
2 * Virtual driver for "simple" device debugging
3 *
4 * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
5 * Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
6 * Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /*
24 * This is a virtual driver to debug the non-image based drivers. A small
25 * python script is provided to connect to it via a socket, allowing
26 * prints to registered programmatically.
27 * Using this, it is possible to test libfprint and fprintd.
28 */
29
30 #define FP_COMPONENT "virtual_device"
31
32 #include "virtual-device-private.h"
33 #include "fpi-log.h"
34
35
4/5
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 117 times.
✗ Branch 4 not taken.
984 G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE)
36
37 #define INSERT_CMD_PREFIX "INSERT "
38 #define REMOVE_CMD_PREFIX "REMOVE "
39 #define SCAN_CMD_PREFIX "SCAN "
40 #define CONT_CMD_PREFIX "CONT "
41 #define ERROR_CMD_PREFIX "ERROR "
42 #define RETRY_CMD_PREFIX "RETRY "
43 #define FINGER_CMD_PREFIX "FINGER "
44 #define SLEEP_CMD_PREFIX "SLEEP "
45 #define SET_ENROLL_STAGES_PREFIX "SET_ENROLL_STAGES "
46 #define SET_SCAN_TYPE_PREFIX "SET_SCAN_TYPE "
47 #define SET_CANCELLATION_PREFIX "SET_CANCELLATION_ENABLED "
48 #define SET_KEEP_ALIVE_PREFIX "SET_KEEP_ALIVE "
49
50 #define LIST_CMD "LIST"
51 #define UNPLUG_CMD "UNPLUG"
52
53 static void
54 522 maybe_continue_current_action (FpDeviceVirtualDevice *self)
55 {
56 522 FpDevice *dev = FP_DEVICE (self);
57
58
2/2
✓ Branch 0 taken 518 times.
✓ Branch 1 taken 4 times.
522 if (self->sleep_timeout_id)
59 return;
60
61
1/2
✓ Branch 0 taken 518 times.
✗ Branch 1 not taken.
518 g_assert (self->wait_command_id == 0);
62
63
8/9
✓ Branch 1 taken 244 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 219 times.
518 switch (fpi_device_get_current_action (dev))
64 {
65 case FPI_DEVICE_ACTION_ENROLL:
66 244 FP_DEVICE_GET_CLASS (self)->enroll (dev);
67 244 break;
68
69 case FPI_DEVICE_ACTION_VERIFY:
70 14 FP_DEVICE_GET_CLASS (self)->verify (dev);
71 14 break;
72
73 case FPI_DEVICE_ACTION_IDENTIFY:
74 11 FP_DEVICE_GET_CLASS (self)->identify (dev);
75 11 break;
76
77 case FPI_DEVICE_ACTION_LIST:
78 8 FP_DEVICE_GET_CLASS (self)->list (dev);
79 8 break;
80
81 case FPI_DEVICE_ACTION_DELETE:
82 5 FP_DEVICE_GET_CLASS (self)->delete (dev);
83 5 break;
84
85 case FPI_DEVICE_ACTION_OPEN:
86 7 FP_DEVICE_GET_CLASS (self)->open (dev);
87 7 break;
88
89 case FPI_DEVICE_ACTION_CLOSE:
90 10 FP_DEVICE_GET_CLASS (self)->close (dev);
91 10 break;
92
93 case FPI_DEVICE_ACTION_CLEAR_STORAGE:
94 FP_DEVICE_GET_CLASS (self)->clear_storage (dev);
95 break;
96
97 /* Not implemented/nothing to do. */
98 case FPI_DEVICE_ACTION_NONE:
99 case FPI_DEVICE_ACTION_PROBE:
100 case FPI_DEVICE_ACTION_CAPTURE:
101 default:
102 break;
103 }
104 }
105
106 static gboolean
107 187 sleep_timeout_cb (gpointer data)
108 {
109 187 FpDeviceVirtualDevice *self = data;
110
111 187 self->sleep_timeout_id = 0;
112
113
1/2
✓ Branch 1 taken 187 times.
✗ Branch 2 not taken.
187 if (g_cancellable_is_cancelled (self->cancellable))
114 return FALSE;
115
116 187 g_debug ("Sleeping completed");
117 187 maybe_continue_current_action (self);
118
119 187 return FALSE;
120 }
121
122 static gboolean
123 12 wait_for_command_timeout (gpointer data)
124 {
125 12 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (data);
126 12 FpiDeviceAction action;
127 12 GError *error = NULL;
128
129 12 self->wait_command_id = 0;
130
131 12 action = fpi_device_get_current_action (FP_DEVICE (self));
132
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (action == FPI_DEVICE_ACTION_LIST || action == FPI_DEVICE_ACTION_DELETE)
133 {
134 11 self->ignore_wait = TRUE;
135 11 maybe_continue_current_action (self);
136 11 self->ignore_wait = FALSE;
137
138 11 return FALSE;
139 }
140
141 1 error = g_error_new (G_IO_ERROR, G_IO_ERROR_TIMED_OUT, "No commands arrived in time to run!");
142 1 fpi_device_action_error (FP_DEVICE (self), error);
143
144 1 return FALSE;
145 }
146
147 gboolean
148 614 process_cmds (FpDeviceVirtualDevice * self,
149 gboolean scan,
150 char **scan_id,
151 GError **error)
152 {
153 614 gboolean removed;
154
155
2/4
✓ Branch 1 taken 614 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 614 times.
✗ Branch 4 not taken.
1228 if (g_cancellable_is_cancelled (self->cancellable) ||
156
2/2
✓ Branch 1 taken 606 times.
✓ Branch 2 taken 8 times.
1228 (fpi_device_get_current_action (FP_DEVICE (self)) != FPI_DEVICE_ACTION_NONE &&
157 614 g_cancellable_is_cancelled (fpi_device_get_cancellable (FP_DEVICE (self)))))
158 {
159 8 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
160 "Operation was cancelled");
161 8 return TRUE;
162 }
163
164
2/2
✓ Branch 0 taken 318 times.
✓ Branch 1 taken 300 times.
618 while (self->pending_commands->len > 0)
165 {
166 318 g_autofree gchar *cmd = NULL;
167
168 /* TODO: g_ptr_array_steal_index requires GLib 2.58, we depend on 2.56 */
169 318 cmd = g_ptr_array_index (self->pending_commands, 0);
170 318 g_ptr_array_index (self->pending_commands, 0) = NULL;
171 318 g_ptr_array_remove_index (self->pending_commands, 0);
172
173 318 g_debug ("Processing command %s", cmd);
174
175 /* These are always processed. */
176
5/6
✗ Branch 0 not taken.
✓ Branch 1 taken 318 times.
✓ Branch 3 taken 279 times.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 276 times.
318 if (g_str_has_prefix (cmd, INSERT_CMD_PREFIX))
177 {
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 g_assert (self->prints_storage);
179 6 g_hash_table_add (self->prints_storage,
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 g_strdup (cmd + strlen (INSERT_CMD_PREFIX)));
181
182 3 continue;
183 }
184
5/6
✓ Branch 0 taken 315 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 276 times.
✓ Branch 3 taken 39 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 275 times.
315 else if (g_str_has_prefix (cmd, REMOVE_CMD_PREFIX))
185 {
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert (self->prints_storage);
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!g_hash_table_remove (self->prints_storage,
188 1 cmd + strlen (REMOVE_CMD_PREFIX)))
189 g_warning ("ID %s was not found in storage", cmd + strlen (REMOVE_CMD_PREFIX));
190
191 1 continue;
192 }
193
5/6
✓ Branch 0 taken 314 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 275 times.
✓ Branch 3 taken 39 times.
✓ Branch 5 taken 43 times.
✓ Branch 6 taken 232 times.
314 else if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
194 {
195 43 guint64 sleep_ms = g_ascii_strtoull (cmd + strlen (SLEEP_CMD_PREFIX), NULL, 10);
196
197 43 g_debug ("Sleeping %" G_GUINT64_FORMAT "ms", sleep_ms);
198 43 self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self);
199
200 43 return FALSE;
201 }
202
5/6
✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 232 times.
✓ Branch 3 taken 39 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 221 times.
271 else if (g_str_has_prefix (cmd, ERROR_CMD_PREFIX))
203 {
204 11 g_propagate_error (error,
205 11 fpi_device_error_new (g_ascii_strtoull (cmd + strlen (ERROR_CMD_PREFIX), NULL, 10)));
206
207 11 return TRUE;
208 }
209
6/8
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 215 times.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 39 times.
260 else if (!scan && g_str_has_prefix (cmd, CONT_CMD_PREFIX))
210 {
211 return TRUE;
212 }
213
214 /* If we are not scanning, then we have to stop here. */
215 221 if (!scan)
216 {
217 6 g_warning ("Could not process command: %s", cmd);
218 6 break;
219 }
220
221
4/6
✓ Branch 0 taken 215 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 215 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 174 times.
✓ Branch 6 taken 41 times.
215 if (g_str_has_prefix (cmd, SCAN_CMD_PREFIX))
222 {
223
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 if (scan_id)
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
348 *scan_id = g_strdup (cmd + strlen (SCAN_CMD_PREFIX));
225
226 174 return TRUE;
227 }
228
4/6
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 33 times.
✓ Branch 6 taken 8 times.
41 else if (g_str_has_prefix (cmd, RETRY_CMD_PREFIX))
229 {
230 33 g_propagate_error (error,
231 33 fpi_device_retry_new (g_ascii_strtoull (cmd + strlen (RETRY_CMD_PREFIX), NULL, 10)));
232
233 33 return TRUE;
234 }
235
3/6
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 else if (g_str_has_prefix (cmd, FINGER_CMD_PREFIX))
236 8 {
237 8 gboolean finger_present;
238
239 8 finger_present = g_ascii_strtoull (cmd + strlen (FINGER_CMD_PREFIX), NULL, 10) != 0;
240
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
12 fpi_device_report_finger_status_changes (FP_DEVICE (self),
241 finger_present ? FP_FINGER_STATUS_PRESENT : FP_FINGER_STATUS_NONE,
242 finger_present ? FP_FINGER_STATUS_NONE : FP_FINGER_STATUS_PRESENT);
243
244 8 continue;
245 }
246 else
247 {
248 g_warning ("Could not process command: %s", cmd);
249 }
250 }
251
252
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 111 times.
306 if (self->ignore_wait)
253 return TRUE;
254
255 111 g_object_get (self, "removed", &removed, NULL);
256
257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111 times.
111 g_assert (self->wait_command_id == 0);
258
4/4
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 99 times.
111 if (!scan || removed)
259 12 self->wait_command_id = g_timeout_add (500, wait_for_command_timeout, self);
260 return FALSE;
261 }
262
263 static void
264 write_key_to_listener (void *key, void *val, void *user_data)
265 {
266 FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (user_data);
267
268 if (!fpi_device_virtual_listener_write_sync (listener, key, strlen (key), NULL) ||
269 !fpi_device_virtual_listener_write_sync (listener, "\n", 1, NULL))
270 g_warning ("Error writing reply to LIST command");
271 }
272
273 static void
274 467 recv_instruction_cb (GObject *source_object,
275 GAsyncResult *res,
276 gpointer user_data)
277 {
278 467 g_autoptr(GError) error = NULL;
279 467 FpiDeviceVirtualListener *listener = FPI_DEVICE_VIRTUAL_LISTENER (source_object);
280 467 gsize bytes;
281
282 467 bytes = fpi_device_virtual_listener_read_finish (listener, res, &error);
283 467 fp_dbg ("Got instructions of length %" G_GSIZE_FORMAT, bytes);
284
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 467 times.
467 if (error)
286 {
287 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
288 return;
289
290 g_warning ("Error receiving instruction data: %s", error->message);
291 return;
292 }
293
294
1/2
✓ Branch 0 taken 467 times.
✗ Branch 1 not taken.
467 if (bytes > 0)
295 {
296 467 FpDeviceVirtualDevice *self;
297 467 g_autofree char *cmd = NULL;
298
299 467 self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
300
301 467 cmd = g_strndup (self->recv_buf, bytes);
302 467 fp_dbg ("Received command %s", cmd);
303
304
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 467 times.
✓ Branch 3 taken 467 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 467 times.
467 if (g_str_has_prefix (cmd, LIST_CMD))
305 {
306 if (self->prints_storage)
307 g_hash_table_foreach (self->prints_storage, write_key_to_listener, listener);
308 }
309
5/6
✓ Branch 0 taken 467 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 428 times.
✓ Branch 3 taken 39 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 426 times.
467 else if (g_str_has_prefix (cmd, UNPLUG_CMD))
310 {
311 2 fpi_device_remove (FP_DEVICE (self));
312 2 maybe_continue_current_action (self);
313 }
314
5/6
✓ Branch 0 taken 465 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 380 times.
✓ Branch 5 taken 73 times.
✓ Branch 6 taken 12 times.
465 else if (g_str_has_prefix (cmd, SET_ENROLL_STAGES_PREFIX))
315 {
316 73 guint stages;
317
318 73 stages = g_ascii_strtoull (cmd + strlen (SET_ENROLL_STAGES_PREFIX), NULL, 10);
319 73 fpi_device_set_nr_enroll_stages (FP_DEVICE (self), stages);
320 }
321
5/6
✓ Branch 0 taken 392 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 206 times.
✓ Branch 3 taken 186 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 200 times.
392 else if (g_str_has_prefix (cmd, SET_SCAN_TYPE_PREFIX))
322 {
323 6 const char *scan_type = cmd + strlen (SET_SCAN_TYPE_PREFIX);
324 473 g_autoptr(GEnumClass) scan_types = g_type_class_ref (fp_scan_type_get_type ());
325 6 GEnumValue *value = g_enum_get_value_by_nick (scan_types, scan_type);
326
327
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (value)
328 4 fpi_device_set_scan_type (FP_DEVICE (self), value->value);
329 else
330 2 g_warning ("Scan type '%s' not found", scan_type);
331 }
332
4/6
✓ Branch 0 taken 386 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 384 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
386 else if (g_str_has_prefix (cmd, SET_CANCELLATION_PREFIX))
333 {
334 4 self->supports_cancellation = g_ascii_strtoull (
335 2 cmd + strlen (SET_CANCELLATION_PREFIX), NULL, 10) != 0;
336
337 2 g_debug ("Cancellation support toggled: %d",
338 self->supports_cancellation);
339 }
340
5/6
✓ Branch 0 taken 384 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 270 times.
✓ Branch 5 taken 68 times.
✓ Branch 6 taken 46 times.
384 else if (g_str_has_prefix (cmd, SET_KEEP_ALIVE_PREFIX))
341 {
342 136 self->keep_alive = g_ascii_strtoull (
343 68 cmd + strlen (SET_KEEP_ALIVE_PREFIX), NULL, 10) != 0;
344
345 68 g_debug ("Keep alive toggled: %d", self->keep_alive);
346 }
347 else
348 {
349 316 g_ptr_array_add (self->pending_commands, g_steal_pointer (&cmd));
350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 316 times.
316 g_clear_handle_id (&self->wait_command_id, g_source_remove);
351
352 316 maybe_continue_current_action (self);
353 }
354 }
355
356
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 467 times.
467 fpi_device_virtual_listener_connection_close (listener);
357 }
358
359 static void
360 467 recv_instruction (FpDeviceVirtualDevice *self)
361 {
362 467 fpi_device_virtual_listener_read (self->listener,
363 FALSE,
364 467 self->recv_buf,
365 sizeof (self->recv_buf),
366 recv_instruction_cb,
367 self);
368 467 }
369
370 static void
371 467 on_listener_connected (FpiDeviceVirtualListener *listener,
372 gpointer user_data)
373 {
374 467 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (user_data);
375
376 467 recv_instruction (self);
377 467 }
378
379 static void
380 104 dev_init (FpDevice *dev)
381 {
382 104 g_autoptr(GError) error = NULL;
383
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
104 g_autoptr(GCancellable) cancellable = NULL;
384
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
104 g_autoptr(FpiDeviceVirtualListener) listener = NULL;
385 104 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
386
387 104 G_DEBUG_HERE ();
388
389 104 self->ignore_wait = TRUE;
390
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 97 times.
104 if (!process_cmds (self, FALSE, NULL, &error))
391 {
392 7 self->ignore_wait = FALSE;
393 7 return;
394 }
395 97 self->ignore_wait = FALSE;
396
397
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 93 times.
97 if (error)
398 {
399 4 fpi_device_open_complete (dev, g_steal_pointer (&error));
400 4 return;
401 }
402
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 88 times.
93 else if (self->listener)
403 {
404 5 fpi_device_open_complete (dev, NULL);
405 5 return;
406 }
407
408 88 listener = fpi_device_virtual_listener_new ();
409 88 cancellable = g_cancellable_new ();
410
411
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
88 if (!fpi_device_virtual_listener_start (listener,
412 88 fpi_device_get_virtual_env (FP_DEVICE (self)),
413 cancellable,
414 on_listener_connected,
415 self,
416 &error))
417 {
418 fpi_device_open_complete (dev, g_steal_pointer (&error));
419 return;
420 }
421
422 88 self->listener = g_steal_pointer (&listener);
423 88 self->cancellable = g_steal_pointer (&cancellable);
424
425
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
88 fpi_device_open_complete (dev, NULL);
426 }
427
428 gboolean
429 333 start_scan_command (FpDeviceVirtualDevice *self,
430 char **scan_id,
431 GError **error)
432 {
433 666 g_autoptr(GError) local_error = NULL;
434 333 gboolean cont;
435
436
2/2
✓ Branch 1 taken 76 times.
✓ Branch 2 taken 257 times.
333 if (fp_device_get_finger_status (FP_DEVICE (self)) == FP_FINGER_STATUS_NONE)
437 76 self->injected_synthetic_cmd = FALSE;
438
439 333 cont = process_cmds (self, TRUE, scan_id, &local_error);
440 /* We report finger needed if we are waiting for instructions
441 * (i.e. we did not get an explicit SLEEP command).
442 */
443
2/2
✓ Branch 0 taken 317 times.
✓ Branch 1 taken 16 times.
333 if (!self->sleep_timeout_id)
444 {
445 317 fpi_device_report_finger_status_changes (FP_DEVICE (self),
446 FP_FINGER_STATUS_NEEDED,
447 FP_FINGER_STATUS_NONE);
448 }
449
450
2/2
✓ Branch 0 taken 217 times.
✓ Branch 1 taken 116 times.
333 if (!cont)
451 return FALSE;
452
453 /* Scan or error*/
454 217 fpi_device_report_finger_status_changes (FP_DEVICE (self),
455 FP_FINGER_STATUS_NEEDED,
456 FP_FINGER_STATUS_NONE);
457
458
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 174 times.
217 if (local_error)
459 43 g_propagate_error (error, g_steal_pointer (&local_error));
460 else
461 174 fpi_device_report_finger_status_changes (FP_DEVICE (self),
462 FP_FINGER_STATUS_PRESENT,
463 FP_FINGER_STATUS_NONE);
464
465 return TRUE;
466 }
467
468 gboolean
469 188 should_wait_to_sleep (FpDeviceVirtualDevice *self,
470 const char *scan_id,
471 GError *error)
472 {
473 188 const gchar *cmd;
474
475
1/2
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
188 if (self->sleep_timeout_id)
476 return TRUE;
477
478
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 118 times.
188 if (!self->pending_commands->len)
479 return FALSE;
480
481 70 cmd = g_ptr_array_index (self->pending_commands, 0);
482
483
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✓ Branch 3 taken 70 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 62 times.
70 if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX))
484 {
485 8 g_autoptr(GError) local_error = NULL;
486 8 process_cmds (self, FALSE, NULL, &local_error);
487
488
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
489 return FALSE;
490
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 g_assert (!self->injected_synthetic_cmd);
492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 g_assert (self->sleep_timeout_id != 0);
493
494
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (!self->pending_commands->len)
495 {
496 2 g_autofree char *injected_cmd = NULL;
497
498
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (scan_id)
499 2 injected_cmd = g_strconcat (SCAN_CMD_PREFIX, scan_id, NULL);
500 else if (error && error->domain == FP_DEVICE_ERROR)
501 injected_cmd = g_strdup_printf (ERROR_CMD_PREFIX " %d", error->code);
502 else if (error && error->domain == FP_DEVICE_RETRY)
503 injected_cmd = g_strdup_printf (RETRY_CMD_PREFIX " %d", error->code);
504 else
505 return TRUE;
506
507 2 g_debug ("Sleeping now, command queued for later: %s", injected_cmd);
508
509 2 g_ptr_array_insert (self->pending_commands, 0, g_steal_pointer (&injected_cmd));
510 2 self->injected_synthetic_cmd = TRUE;
511 }
512 }
513
514 70 return self->sleep_timeout_id != 0;
515 }
516
517 static void
518 34 dev_verify (FpDevice *dev)
519 {
520 34 g_autoptr(GError) error = NULL;
521 34 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
522
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
34 g_autofree char *scan_id = NULL;
523
524
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 14 times.
34 if (!start_scan_command (self, &scan_id, &error))
525 return;
526
527
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 11 times.
20 if (scan_id)
528 {
529 9 g_autoptr(FpPrint) new_scan = NULL;
530 9 GVariant *data = NULL;
531 9 FpPrint *print;
532 9 gboolean success;
533
534 9 g_debug ("Virtual device scanned print %s", scan_id);
535 9 fpi_device_get_verify_data (dev, &print);
536
537 9 new_scan = fp_print_new (dev);
538 9 fpi_print_set_type (new_scan, FPI_PRINT_RAW);
539
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (self->prints_storage)
540 3 fpi_print_set_device_stored (new_scan, TRUE);
541 9 data = g_variant_new_string (scan_id);
542 9 g_object_set (new_scan, "fpi-data", data, NULL);
543
544
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
9 if (self->prints_storage && !g_hash_table_contains (self->prints_storage, scan_id))
545 {
546
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 g_clear_object (&new_scan);
547 success = FALSE;
548 }
549 else
550 {
551 7 success = fp_print_equal (print, new_scan);
552 }
553
554
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 if (!self->match_reported)
555 {
556 8 self->match_reported = TRUE;
557 8 fpi_device_verify_report (dev,
558 success ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL,
559 8 g_steal_pointer (&new_scan),
560 NULL);
561 }
562 }
563
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 else if (error)
564 {
565 11 g_debug ("Virtual device scan failed with error: %s", error->message);
566 }
567
568 20 fpi_device_report_finger_status_changes (FP_DEVICE (self),
569 FP_FINGER_STATUS_NONE,
570 FP_FINGER_STATUS_PRESENT);
571
572
4/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 5 times.
20 if (error && error->domain == FP_DEVICE_RETRY)
573 6 fpi_device_verify_report (dev, FPI_MATCH_ERROR, NULL, g_steal_pointer (&error));
574
575
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 1 times.
20 if (should_wait_to_sleep (self, scan_id, error))
576 return;
577
578 19 self->match_reported = FALSE;
579 19 fpi_device_verify_complete (dev, g_steal_pointer (&error));
580 }
581
582 static void
583 274 dev_enroll (FpDevice *dev)
584 {
585 274 g_autoptr(GError) error = NULL;
586 274 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
587 274 FpPrint *print = NULL;
588
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 175 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 99 times.
274 g_autofree char *id = NULL;
589
590
2/2
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 92 times.
274 if (!start_scan_command (self, &id, &error))
591 return;
592
593 182 fpi_device_get_enroll_data (dev, &print);
594
595
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 26 times.
182 if (id)
596 {
597 156 GVariant *data;
598 156 gboolean completed;
599
600
4/4
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 55 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 100 times.
156 if (self->prints_storage && g_hash_table_contains (self->prints_storage, id))
601 {
602
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (should_wait_to_sleep (self, id, error))
603 7 return;
604
605 1 fpi_device_enroll_complete (dev, NULL,
606 fpi_device_error_new (FP_DEVICE_ERROR_DATA_DUPLICATE));
607 1 return;
608 }
609
610
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 126 times.
155 if (self->enroll_stages_passed == 0)
611 {
612 29 fpi_print_set_type (print, FPI_PRINT_RAW);
613 29 data = g_variant_new_string (id);
614 29 g_object_set (print, "fpi-data", data, NULL);
615 }
616 else
617 {
618 126 gboolean changed;
619
620 126 g_object_get (print, "fpi-data", &data, NULL);
621 126 changed = !g_str_equal (id, g_variant_get_string (data, NULL));
622 126 g_variant_unref (data);
623
624
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 120 times.
126 if (changed)
625 {
626 6 g_set_error (&error, FP_DEVICE_RETRY, FP_DEVICE_RETRY_GENERAL, "ID Mismatch");
627 6 fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL,
628 6 g_steal_pointer (&error));
629
630
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (!should_wait_to_sleep (self, id, error))
631 6 self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
632 6 return;
633 }
634 }
635
636 149 self->enroll_stages_passed++;
637 149 completed = self->enroll_stages_passed == fp_device_get_nr_enroll_stages (FP_DEVICE (self));
638 149 fpi_device_report_finger_status_changes (FP_DEVICE (self),
639 completed ?
640 FP_FINGER_STATUS_NEEDED :
641 FP_FINGER_STATUS_NONE,
642 FP_FINGER_STATUS_PRESENT);
643
644 149 fpi_device_enroll_progress (dev, self->enroll_stages_passed, print, NULL);
645
646
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 120 times.
149 if (completed)
647 {
648
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 10 times.
29 if (self->prints_storage)
649 {
650 19 fpi_print_set_device_stored (print, TRUE);
651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
38 g_hash_table_add (self->prints_storage, g_strdup (id));
652 }
653
654 29 fpi_device_enroll_complete (dev, g_object_ref (print), NULL);
655 29 self->enroll_stages_passed = 0;
656 }
657
2/2
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 6 times.
120 else if (!should_wait_to_sleep (self, id, error))
658 {
659 114 self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
660 }
661 }
662 else
663 {
664 26 fpi_device_report_finger_status_changes (FP_DEVICE (self),
665 FP_FINGER_STATUS_NONE,
666 FP_FINGER_STATUS_PRESENT);
667
668
2/4
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
26 if (error && error->domain == FP_DEVICE_RETRY)
669 {
670 26 fpi_device_enroll_progress (dev, self->enroll_stages_passed, NULL, g_steal_pointer (&error));
671
672
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 if (!should_wait_to_sleep (self, id, error))
673 26 self->sleep_timeout_id = g_idle_add (sleep_timeout_cb, self);
674 }
675 else
676 {
677 if (should_wait_to_sleep (self, id, error))
678 return;
679
680 self->enroll_stages_passed = 0;
681 fpi_device_enroll_complete (dev, NULL, g_steal_pointer (&error));
682 }
683 }
684 }
685
686 static void
687 8 dev_cancel (FpDevice *dev)
688 {
689 8 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
690
691
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (self->injected_synthetic_cmd)
692 {
693 self->injected_synthetic_cmd = FALSE;
694 g_ptr_array_remove_index (self->pending_commands, 0);
695 }
696
697
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (!self->supports_cancellation)
698 return;
699
700 6 g_debug ("Got cancellation!");
701
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 g_clear_handle_id (&self->sleep_timeout_id, g_source_remove);
702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 g_clear_handle_id (&self->wait_command_id, g_source_remove);
703
704 6 maybe_continue_current_action (self);
705 }
706
707 static void
708 161 stop_listener (FpDeviceVirtualDevice *self)
709 {
710 161 g_cancellable_cancel (self->cancellable);
711
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 73 times.
161 g_clear_object (&self->cancellable);
712
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 73 times.
161 g_clear_object (&self->listener);
713 161 }
714
715 static void
716 103 dev_deinit (FpDevice *dev)
717 {
718 103 g_autoptr(GError) error = NULL;
719 103 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev);
720
721 103 self->ignore_wait = TRUE;
722
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 93 times.
103 if (!process_cmds (self, FALSE, NULL, &error))
723 {
724 10 self->ignore_wait = FALSE;
725 10 return;
726 }
727 93 self->ignore_wait = FALSE;
728
729
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 91 times.
93 if (error)
730 {
731 2 fpi_device_close_complete (dev, g_steal_pointer (&error));
732 2 return;
733 }
734
735
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 8 times.
91 if (!self->keep_alive)
736 {
737 83 stop_listener (self);
738 83 self->supports_cancellation = TRUE;
739 }
740
741 91 self->enroll_stages_passed = 0;
742 91 self->match_reported = FALSE;
743
744
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
91 fpi_device_close_complete (dev, NULL);
745 }
746
747 static void
748 78 fpi_device_virtual_device_finalize (GObject *object)
749 {
750 78 FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (object);
751
752 78 G_DEBUG_HERE ();
753 78 stop_listener (self);
754
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 g_clear_pointer (&self->pending_commands, g_ptr_array_unref);
755 78 G_OBJECT_CLASS (fpi_device_virtual_device_parent_class)->finalize (object);
756 78 }
757
758 static void
759 86 fpi_device_virtual_device_init (FpDeviceVirtualDevice *self)
760 {
761 86 self->supports_cancellation = TRUE;
762 86 self->pending_commands = g_ptr_array_new_with_free_func (g_free);
763 86 }
764
765 static const FpIdEntry driver_ids[] = {
766 { .virtual_envvar = "FP_VIRTUAL_DEVICE", },
767 { .virtual_envvar = NULL }
768 };
769
770 static void
771 117 fpi_device_virtual_device_class_init (FpDeviceVirtualDeviceClass *klass)
772 {
773 117 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
774 117 GObjectClass *object_class = G_OBJECT_CLASS (klass);
775
776 117 object_class->finalize = fpi_device_virtual_device_finalize;
777
778 117 dev_class->id = FP_COMPONENT;
779 117 dev_class->full_name = "Virtual device for debugging";
780 117 dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
781 117 dev_class->id_table = driver_ids;
782 117 dev_class->nr_enroll_stages = 5;
783
784 117 dev_class->open = dev_init;
785 117 dev_class->close = dev_deinit;
786 117 dev_class->verify = dev_verify;
787 117 dev_class->enroll = dev_enroll;
788 117 dev_class->cancel = dev_cancel;
789
790 117 fpi_device_class_auto_initialize_features (dev_class);
791 117 }
792