GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 90.9% 339 / 0 / 373
Functions: 95.5% 21 / 0 / 22
Branches: 69.6% 211 / 0 / 303

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