/
fingerprint.c
2715 lines (2293 loc) · 74.8 KB
/
fingerprint.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @file fingerprint.c
*
* Fingerprint daemon tracking module for the Mode Control Entity
* <p>
* Copyright (c) 2015-2019 Jolla Ltd.
* <p>
* @author Simo Piiroinen <simo.piiroinen@jollamobile.com>
*
* mce is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* mce is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mce. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../mce.h"
#include "../mce-lib.h"
#include "../mce-log.h"
#include "../mce-dbus.h"
#include "../mce-setting.h"
#include "../evdev.h"
#include <linux/input.h>
#include <gmodule.h>
/* ========================================================================= *
* Types
* ========================================================================= */
/** Return values for requests made to fingerprint daemon
*
* Keep fpreply_repr() in sync with any changes made here.
*/
typedef enum fpreply_t
{
/** Operation successfully started */
FPREPLY_STARTED = 0,
/** Unspecified (low level) failure */
FPREPLY_FAILED = 1,
/** Abort() while already idle */
FPREPLY_ALREADY_IDLE = 2,
/** Abort/Enroll/Identify() while busy */
FPREPLY_ALREADY_BUSY = 3,
/** Not allowed */
FPREPLY_DENIED = 4,
/** Enroll() key that already exists */
FPREPLY_KEY_ALREADY_EXISTS = 5,
/** Remove() key that does not exist */
FPREPLY_KEY_DOES_NOT_EXIST = 6,
/** Identify() without having any keys */
FPREPLY_NO_KEYS_AVAILABLE = 7,
/** Null or otherwise illegal key name */
FPREPLY_KEY_IS_INVALID = 8,
} fpreply_t;
/** Resulting events from accepted fingerprint daemon requests
*
* Keep fpresult_repr() in sync with any changes made here.
*/
typedef enum fpresult_t
{
FPRESULT_ABORTED,
FPRESULT_FAILED,
FPRESULT_IDENTIFIED,
FPRESULT_VERIFIED,
} fpresult_t;
/** Fingerprint daemon ipc operation state
*
* Keep fpopstate_repr() in sync with any changes made here.
*/
typedef enum fpopstate_t
{
/** Initial state */
FPOPSTATE_INITIALIZE,
/** Wait until operation is required and fpd is idle */
FPOPSTATE_WAITING,
/** Send asynchronous dbus method call and wait for reply */
FPOPSTATE_REQUEST,
/** Wait for operation results / errors / cancellation */
FPOPSTATE_PENDING,
/* Operation was successfully finished */
FPOPSTATE_SUCCESS,
/* Operation failed */
FPOPSTATE_FAILURE,
/* Send asynchronous abort dbus method call and wait for reply */
FPOPSTATE_ABORT,
/** Wait for fpd to make transition to idle state */
FPOPSTATE_ABORTING,
/** Opearation was aborted */
FPOPSTATE_ABORTED,
/** Delay in between operation retry attempts */
FPOPSTATE_THROTTLING,
/** Number of possible states */
FPOPSTATE_NUMOF
} fpopstate_t;
/** State machine for performing ipc operations with fingerprint daemon
*
* The happy path for making request to fingerprint daemon over dbus is:
*
* 1. Wait for daemon to be idle
* 2. Request start of operation
* 3. Wait for operation started acknowledgement
* 4. Wait for operation result
*
* To facilitate overlapping use by multiple clients, all clients must
* expect requests to be denied (while busy with requests from other
* clients), daemon dropping out of system bus and coming back up, and
* illogical seeming state transitions and be prepared to retry until
* succeeding.
*
* The fpoperation_t structure contains bookkeeping data for generic
* state machine that can be used to perform any fingerprint daemon
* request by providing suitable hooks.
*/
typedef struct fpoperation_t fpoperation_t;
struct fpoperation_t
{
/** State machine name */
const char *fpo_name;
/** Current state */
fpopstate_t fpo_state;
/** Expected/tracked fpstate
*
* Used for detecting situations where we're obviously out of
* sync with what is going on at the fingerprint daemon side.
*/
fpstate_t fpo_fpstate;
/** Pending async D-Bus method call
*
* This is either the operation this state machine is expected
* to perform, or abort used for canceling successfully started
* request.
*/
DBusPendingCall *fpo_pending;
/** Pending timeout
*
* Used for throttling consecutive operations, so that we allow
* time for system state changes affecting the use of this state
* machine to occur.
*/
guint fpo_timer;
/** Hook for entering a state */
void (*fpo_enter_cb)(fpoperation_t *self);
/** Hook for leaving a state */
void (*fpo_leave_cb)(fpoperation_t *self);
/** Hook for evaluating staying in a state */
void (*fpo_eval_cb) (fpoperation_t *self);
/** Hook for handling operation result events */
void (*fpo_result_cb)(fpoperation_t *self, fpresult_t event);
};
/* ========================================================================= *
* Prototypes
* ========================================================================= */
/* ------------------------------------------------------------------------- *
* FPREPLY
* ------------------------------------------------------------------------- */
static const char *fpreply_repr(fpreply_t val);
/* ------------------------------------------------------------------------- *
* FPRESULT
* ------------------------------------------------------------------------- */
static const char *fpresult_repr(fpresult_t event);
/* ------------------------------------------------------------------------- *
* FPOPSTATE
* ------------------------------------------------------------------------- */
static const char *fpopstate_repr(fpopstate_t state);
/* ------------------------------------------------------------------------- *
* FPOPERATION
* ------------------------------------------------------------------------- */
static const char *fpoperation_name (const fpoperation_t *self);
static fpopstate_t fpoperation_state (const fpoperation_t *self);
static void fpoperation_enter (fpoperation_t *self);
static void fpoperation_leave (fpoperation_t *self);
static bool fpoperation_eval_overrides (fpoperation_t *self);
static void fpoperation_eval (fpoperation_t *self);
static void fpoperation_result (fpoperation_t *self, fpresult_t event);
static void fpoperation_trans (fpoperation_t *self, fpopstate_t state);
static fpstate_t fpoperation_get_fpstate (const fpoperation_t *self);
static void fpoperation_set_fpstate (fpoperation_t *self, fpstate_t state);
static void fpoperation_cancel_timout (fpoperation_t *self);
static bool fpoperation_detach_timout (fpoperation_t *self);
static void fpoperation_attach_timeout (fpoperation_t *self, int delay, GSourceFunc cb);
static gboolean fpoperation_trigger_fpwakeup_cb(gpointer aptr);
static gboolean fpoperation_throttling_ended_cb(gpointer aptr);
static void fpoperation_cancel_pending_call(fpoperation_t *self);
static bool fpoperation_detach_pending_call(fpoperation_t *self, DBusPendingCall *pc);
static void fpoperation_attach_pending_call(fpoperation_t *self, DBusPendingCall *pc);
static void fpoperation_identify_reply_cb (DBusPendingCall *pc, void *aptr);
static void fpoperation_start_identify (fpoperation_t *self);
static void fpoperation_abort_reply_cb (DBusPendingCall *pc, void *aptr);
static void fpoperation_start_abort (fpoperation_t *self);
/* ------------------------------------------------------------------------- *
* FPIDENTIFY
* ------------------------------------------------------------------------- */
static void fpidentify_enter_cb (fpoperation_t *self);
static void fpidentify_leave_cb (fpoperation_t *self);
static void fpidentify_eval_cb (fpoperation_t *self);
static void fpidentify_result_cb(fpoperation_t *self, fpresult_t event);
/* ------------------------------------------------------------------------- *
* FINGERPRINT_DATA
* ------------------------------------------------------------------------- */
static gpointer fingerprint_data_create (const char *name);
static void fingerprint_data_detete_cb(gpointer aptr);
static void fingerprint_data_flush (void);
static void fingerprint_data_remove (const char *name);
static void fingerprint_data_add (const char *name);
static bool fingerprint_data_exists (void);
static void fingerprint_data_init (void);
static void fingerprint_data_quit (void);
/* ------------------------------------------------------------------------- *
* FINGERPRINT_LED_SCANNING
* ------------------------------------------------------------------------- */
static void fingerprint_led_scanning_activate(bool activate);
/* ------------------------------------------------------------------------- *
* FINGERPRINT_LED_ACQUIRED
* ------------------------------------------------------------------------- */
static void fingerprint_led_acquired_activate(bool activate);
static gboolean fingerprint_led_acquired_timer_cb(gpointer aptr);
static void fingerprint_led_acquired_trigger (void);
static void fingerprint_led_acquired_cancel (void);
/* ------------------------------------------------------------------------- *
* FINGERPRINT_DATAPIPE
* ------------------------------------------------------------------------- */
static void fingerprint_datapipe_set_fpstate (fpstate_t state);
static bool fingerprint_datapipe_evaluate_enroll_in_progress(void);
static void fingerprint_datapipe_update_enroll_in_progress (void);
static void fingerprint_datapipe_generate_activity (void);
static void fingerprint_datapipe_fpd_service_state_cb (gconstpointer data);
static void fingerprint_datapipe_system_state_cb (gconstpointer data);
static void fingerprint_datapipe_devicelock_state_cb (gconstpointer data);
static void fingerprint_datapipe_submode_cb (gconstpointer data);
static void fingerprint_datapipe_display_state_next_cb (gconstpointer data);
static void fingerprint_datapipe_interaction_expected_cb (gconstpointer data);
static void fingerprint_datapipe_topmost_window_pid_cb (gconstpointer data);
static void fingerprint_datapipe_proximity_sensor_actual_cb (gconstpointer data);
static void fingerprint_datapipe_lid_sensor_filtered_cb (gconstpointer data);
static void fingerprint_datapipe_keypress_event_cb (gconstpointer const data);
static void fingerprint_datapipe_init (void);
static void fingerprint_datapipe_quit (void);
/* ------------------------------------------------------------------------- *
* FINGERPRINT_SETTING
* ------------------------------------------------------------------------- */
static void fingerprint_setting_cb (GConfClient *const gcc, const guint id, GConfEntry *const entry, gpointer const data);
static void fingerprint_setting_init(void);
static void fingerprint_setting_quit(void);
/* ------------------------------------------------------------------------- *
* FINGERPRINT_DBUS
* ------------------------------------------------------------------------- */
static gboolean fingerprint_dbus_fpstate_changed_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpacquired_info_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpadded_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpremoved_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpidentified_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpaborted_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpfailed_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpverified_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fperror_cb (DBusMessage *const msg);
static gboolean fingerprint_dbus_fpprogress_cb (DBusMessage *const msg);
static void fingerprint_dbus_init (void);
static void fingerprint_dbus_quit (void);
static void fingerprint_dbus_fpstate_query_cb (DBusPendingCall *pc, void *aptr);
static void fingerprint_dbus_fpstate_query_cancel(void);
static void fingerprint_dbus_fpstate_query_start (void);
static void fingerprint_dbus_fpdata_query_cb (DBusPendingCall *pc, void *aptr);
static void fingerprint_dbus_fpdata_query_cancel (void);
static void fingerprint_dbus_fpdata_query_start (void);
/* ------------------------------------------------------------------------- *
* FPWAKEUP
* ------------------------------------------------------------------------- */
static bool fpwakeup_is_allowed (void);
static void fpwakeup_set_allowed (bool allowed);
static gboolean fpwakeup_allow_cb (gpointer aptr);
static void fpwakeup_cancel_allow (void);
static void fpwakeup_schedule_allow (void);
static bool fpwakeup_evaluate_allowed (void);
static void fpwakeup_update_allowed (void);
static void fpwakeup_rethink_now (void);
static gboolean fpwakeup_rethink_cb (gpointer aptr);
static void fpwakeup_schedule_rethink (void);
static void fpwakeup_cancel_rethink (void);
static void fpwakeup_propagate_fpstate (void);
static void fpwakeup_propagate_fpresult(fpresult_t event);
static void fpwakeup_propagate_eval (void);
static bool fpwakeup_set_primed (bool prime);
static void fpwakeup_trigger (void);
/* ------------------------------------------------------------------------- *
* G_MODULE
* ------------------------------------------------------------------------- */
const gchar *g_module_check_init(GModule *module);
void g_module_unload (GModule *module);
/* ========================================================================= *
* FINGERPRINT_DATAPIPE
* ========================================================================= */
/** Cached fpd service availability; assume unknown */
static service_state_t fpd_service_state = SERVICE_STATE_UNDEF;
/** Cached system_state; assume unknown */
static system_state_t system_state = MCE_SYSTEM_STATE_UNDEF;
/** Cached devicelock_state ; assume unknown */
static devicelock_state_t devicelock_state = DEVICELOCK_STATE_UNDEFINED;
/** Cached submode ; assume invalid */
static submode_t submode = MCE_SUBMODE_INVALID;
/** Cached target display_state; assume unknown */
static display_state_t display_state_next = MCE_DISPLAY_UNDEF;
/** Interaction expected; assume false */
static bool interaction_expected = false;
/** Cached PID of process owning the topmost window on UI */
static int topmost_window_pid = -1;
/** Cached proximity sensor state */
static cover_state_t proximity_sensor_actual = COVER_UNDEF;
/** Lid cover policy state; assume unknown */
static cover_state_t lid_sensor_filtered = COVER_UNDEF;
/** Cached power key pressed down state */
static bool powerkey_pressed = false;
/* ========================================================================= *
* FINGERPRINT_SETTINGS
* ========================================================================= */
/** Fingerprint wakeup enable mode */
static gint fingerprint_wakeup_mode = MCE_DEFAULT_FPWAKEUP_MODE;
static guint fingerprint_wakeup_mode_setting_id = 0;
static gint fingerprint_allow_delay = MCE_DEFAULT_FPWAKEUP_ALLOW_DELAY;
static guint fingerprint_allow_delay_setting_id = 0;
static gint fingerprint_trigger_delay = MCE_DEFAULT_FPWAKEUP_TRIGGER_DELAY;
static guint fingerprint_trigger_delay_setting_id = 0;
static gint fingerprint_throttle_delay = MCE_DEFAULT_FPWAKEUP_THROTTLE_DELAY;
static guint fingerprint_throttle_delay_setting_id = 0;
/* ========================================================================= *
* MANAGED_STATES
* ========================================================================= */
/** Tracked fpd operational state; assume unknown */
static fpstate_t fpstate = FPSTATE_UNSET;
/** Tracked fingerprint enroll status; assume not in progress */
static bool enroll_in_progress = false;
/** State machine data for handling fpd requests */
static fpoperation_t fpoperation_lut[] =
{
{
.fpo_name = "identify_stm",
.fpo_state = FPOPSTATE_INITIALIZE,
.fpo_fpstate = FPSTATE_UNSET,
.fpo_pending = 0,
.fpo_timer = 0,
.fpo_enter_cb = fpidentify_enter_cb,
.fpo_leave_cb = fpidentify_leave_cb,
.fpo_eval_cb = fpidentify_eval_cb,
.fpo_result_cb = fpidentify_result_cb,
},
};
/* ========================================================================= *
* FPREPLY
* ========================================================================= */
static const char *
fpreply_repr(fpreply_t val)
{
const char *repr = "FPREPLY_UNKNOWN";
#define REPR_VAL(NAME) case NAME: repr = #NAME; break
switch( val ) {
REPR_VAL(FPREPLY_STARTED);
REPR_VAL(FPREPLY_FAILED);
REPR_VAL(FPREPLY_ALREADY_IDLE);
REPR_VAL(FPREPLY_ALREADY_BUSY);
REPR_VAL(FPREPLY_DENIED);
REPR_VAL(FPREPLY_KEY_ALREADY_EXISTS);
REPR_VAL(FPREPLY_KEY_DOES_NOT_EXIST);
REPR_VAL(FPREPLY_NO_KEYS_AVAILABLE);
REPR_VAL(FPREPLY_KEY_IS_INVALID);
default: break;
}
#undef REPR_VAL
return repr;
}
/* ========================================================================= *
* FPRESULT
* ========================================================================= */
static const char *
fpresult_repr(fpresult_t event)
{
static const char * const fpresult_lut[] =
{
[FPRESULT_ABORTED] = "FPRESULT_ABORTED",
[FPRESULT_FAILED] = "FPRESULT_FAILED",
[FPRESULT_IDENTIFIED] = "FPRESULT_IDENTIFIED",
[FPRESULT_VERIFIED] = "FPRESULT_VERIFIED",
};
return fpresult_lut[event];
}
/* ========================================================================= *
* FPOPSTATE
* ========================================================================= */
static const char *
fpopstate_repr(fpopstate_t state)
{
static const char * const fpopstate_lut[FPOPSTATE_NUMOF] = {
[FPOPSTATE_INITIALIZE] = "FPOPSTATE_INITIALIZE",
[FPOPSTATE_WAITING] = "FPOPSTATE_WAITING",
[FPOPSTATE_REQUEST] = "FPOPSTATE_REQUEST",
[FPOPSTATE_PENDING] = "FPOPSTATE_PENDING",
[FPOPSTATE_SUCCESS] = "FPOPSTATE_SUCCESS",
[FPOPSTATE_FAILURE] = "FPOPSTATE_FAILURE",
[FPOPSTATE_ABORT] = "FPOPSTATE_ABORT",
[FPOPSTATE_ABORTING] = "FPOPSTATE_ABORTING",
[FPOPSTATE_ABORTED] = "FPOPSTATE_ABORTED",
[FPOPSTATE_THROTTLING] = "FPOPSTATE_THROTTLING",
};
return fpopstate_lut[state];
}
/* ========================================================================= *
* FPOPERATION
* ========================================================================= */
/** Accessor for operation name
*/
static const char *
fpoperation_name(const fpoperation_t *self)
{
return self->fpo_name ?: "unnamed";
}
/** Accessor for operation state
*/
static fpopstate_t
fpoperation_state(const fpoperation_t *self)
{
return self->fpo_state;
}
/** Handle tasks after entering to a state
*/
static void
fpoperation_enter(fpoperation_t *self)
{
if( self->fpo_enter_cb )
self->fpo_enter_cb(self);
}
/** Handle tasks after leaving a state
*/
static void
fpoperation_leave(fpoperation_t *self)
{
if( self->fpo_leave_cb )
self->fpo_leave_cb(self);
}
/** Handle evaluation of generic rules
*/
static bool
fpoperation_eval_overrides(fpoperation_t *self)
{
bool overridden = false;
/* If fingerprint daemon is not on system bus, cancel any
* ongoing async activity via transition to aborted state.
*/
if( fpstate == FPSTATE_UNSET ) {
switch( fpoperation_state(self) ) {
case FPOPSTATE_INITIALIZE:
case FPOPSTATE_WAITING:
/* Nothing initiated -> NOP */
break;
case FPOPSTATE_REQUEST:
case FPOPSTATE_PENDING:
case FPOPSTATE_SUCCESS:
case FPOPSTATE_FAILURE:
case FPOPSTATE_ABORT:
case FPOPSTATE_ABORTING:
fpoperation_trans(self, FPOPSTATE_ABORTED);
overridden = true;
break;
default:
case FPOPSTATE_ABORTED:
case FPOPSTATE_THROTTLING:
/* No pending ipc -> NOP */
break;
}
}
return overridden;
}
/** Evaluate whether current state is still valid
*/
static void
fpoperation_eval(fpoperation_t *self)
{
if( !fpoperation_eval_overrides(self) ) {
if( self->fpo_eval_cb )
self->fpo_eval_cb(self);
}
}
/** Handle operation result events
*/
static void
fpoperation_result(fpoperation_t *self, fpresult_t event)
{
mce_log(LL_DEBUG, "%s @ %s: got event %s",
fpoperation_name(self),
fpopstate_repr(fpoperation_state(self)),
fpresult_repr(event));
if( self->fpo_result_cb )
self->fpo_result_cb(self, event);
}
/** Handle state transition
*/
static void
fpoperation_trans(fpoperation_t *self, fpopstate_t state)
{
if( self->fpo_state != state ) {
mce_log(LL_DEBUG, "%s @ %s: transition to %s",
fpoperation_name(self),
fpopstate_repr(self->fpo_state),
fpopstate_repr(state));
fpoperation_leave(self);
self->fpo_state = state;
fpoperation_enter(self);
fpwakeup_schedule_rethink();
}
}
/** Accessor for cached fpd state
*/
static fpstate_t
fpoperation_get_fpstate(const fpoperation_t *self)
{
return self->fpo_fpstate;
}
/** Set cached fpd state
*/
static void
fpoperation_set_fpstate(fpoperation_t *self, fpstate_t state)
{
fpstate_t prev = self->fpo_fpstate;
self->fpo_fpstate = state;
if( prev != self->fpo_fpstate ) {
mce_log(LL_DEBUG, "%s @ %s: fpstate: %s -> %s",
fpoperation_name(self),
fpopstate_repr(fpoperation_state(self)),
fpstate_repr(prev),
fpstate_repr(self->fpo_fpstate));
}
}
/** Cancel timer
*/
static void
fpoperation_cancel_timout(fpoperation_t *self)
{
if( self->fpo_timer ) {
g_source_remove(self->fpo_timer),
self->fpo_timer = 0;
}
}
/** Remove timer id from bookkeeping data
*/
static bool
fpoperation_detach_timout(fpoperation_t *self)
{
bool detached = false;
if( self->fpo_timer ) {
self->fpo_timer = 0;
detached = true;
}
return detached;
}
/** Attach timer id to bookkeeping data
*/
static void
fpoperation_attach_timeout(fpoperation_t *self, int delay, GSourceFunc cb)
{
fpoperation_cancel_timout(self);
self->fpo_timer = mce_wakelocked_timeout_add(delay, cb, self);
}
/** Timer callback for triggering fpwakeup
*/
static gboolean
fpoperation_trigger_fpwakeup_cb(gpointer aptr)
{
fpoperation_t *self = aptr;
if( !fpoperation_detach_timout(self) )
goto EXIT;
fpwakeup_trigger();
fpoperation_trans(self, FPOPSTATE_THROTTLING);
EXIT:
return G_SOURCE_REMOVE;
}
/** Timer callback for exiting FPOPSTATE_THROTTLING state
*/
static gboolean
fpoperation_throttling_ended_cb(gpointer aptr)
{
fpoperation_t *self = aptr;
if( !fpoperation_detach_timout(self) )
goto EXIT;
fpoperation_trans(self, FPOPSTATE_WAITING);
EXIT:
return G_SOURCE_REMOVE;
}
/** Cancel pending async dbus method call
*/
static void
fpoperation_cancel_pending_call(fpoperation_t *self)
{
if( self->fpo_pending ) {
dbus_pending_call_cancel(self->fpo_pending);
dbus_pending_call_unref(self->fpo_pending),
self->fpo_pending = 0;
}
}
/** Detach pending async dbus method call from bookkeeping data
*/
static bool
fpoperation_detach_pending_call(fpoperation_t *self, DBusPendingCall *pc)
{
bool detached = false;
if( pc != 0 && self->fpo_pending == pc ) {
//dbus_pending_call_unref(self->fpo_pending),
self->fpo_pending = 0;
detached = true;
}
return detached;
}
/** Attach pending async dbus method call to bookkeeping data
*/
static void
fpoperation_attach_pending_call(fpoperation_t *self, DBusPendingCall *pc)
{
fpoperation_cancel_pending_call(self);
self->fpo_pending = pc;
}
/** Callback for handling reply to FINGERPRINT1_DBUS_REQ_IDENTIFY calls
*/
static void
fpoperation_identify_reply_cb(DBusPendingCall *pc, void *aptr)
{
fpoperation_t *self = aptr;
DBusMessage *rsp = 0;
DBusError err = DBUS_ERROR_INIT;
dbus_int32_t res = 0;
if( !fpoperation_detach_pending_call(self, pc) )
goto EXIT;
if( !(rsp = dbus_pending_call_steal_reply(pc)) ) {
mce_log(LL_WARN, "no reply");
goto EXIT;
}
if( dbus_set_error_from_message(&err, rsp) ||
!dbus_message_get_args(rsp, &err,
DBUS_TYPE_INT32, &res,
DBUS_TYPE_INVALID) ) {
mce_log(LL_WARN, "error: %s: %s", err.name, err.message);
goto EXIT;
}
mce_log(LL_DEBUG, "identify reply: %s", fpreply_repr(res));
switch( res ) {
case FPREPLY_STARTED:
fpoperation_trans(self, FPOPSTATE_PENDING);
break;
default:
fpoperation_trans(self, FPOPSTATE_FAILURE);
break;
}
EXIT:
if( rsp ) dbus_message_unref(rsp);
dbus_error_free(&err);
dbus_pending_call_unref(pc);
return;
}
/** Initiate async FINGERPRINT1_DBUS_REQ_IDENTIFY method call
*/
static void
fpoperation_start_identify(fpoperation_t *self)
{
DBusPendingCall *pc = 0;
dbus_send_ex(FINGERPRINT1_DBUS_SERVICE,
FINGERPRINT1_DBUS_ROOT_OBJECT,
FINGERPRINT1_DBUS_INTERFACE,
FINGERPRINT1_DBUS_REQ_IDENTIFY,
fpoperation_identify_reply_cb,
self, 0,
&pc,
DBUS_TYPE_INVALID);
fpoperation_attach_pending_call(self, pc);
}
/** Callback for handling reply to FINGERPRINT1_DBUS_REQ_ABORT calls
*/
static void
fpoperation_abort_reply_cb(DBusPendingCall *pc, void *aptr)
{
fpoperation_t *self = aptr;
DBusMessage *rsp = 0;
DBusError err = DBUS_ERROR_INIT;
dbus_int32_t res = 0;
if( !fpoperation_detach_pending_call(self, pc) )
goto EXIT;
if( !(rsp = dbus_pending_call_steal_reply(pc)) ) {
mce_log(LL_WARN, "no reply");
goto EXIT;
}
if( dbus_set_error_from_message(&err, rsp) ||
!dbus_message_get_args(rsp, &err,
DBUS_TYPE_INT32, &res,
DBUS_TYPE_INVALID) ) {
mce_log(LL_WARN, "error: %s: %s", err.name, err.message);
goto EXIT;
}
mce_log(LL_DEBUG, "abort reply: %s", fpreply_repr(res));
switch( res ) {
case FPREPLY_STARTED:
fpoperation_trans(self, FPOPSTATE_ABORTING);
break;
case FPREPLY_ALREADY_IDLE:
fpoperation_trans(self, FPOPSTATE_ABORTED);
break;
default:
fpoperation_trans(self, FPOPSTATE_FAILURE);
break;
}
EXIT:
if( rsp ) dbus_message_unref(rsp);
dbus_error_free(&err);
dbus_pending_call_unref(pc);
return;
}
/** Initiate async FINGERPRINT1_DBUS_REQ_ABORT method call
*/
static void
fpoperation_start_abort(fpoperation_t *self)
{
DBusPendingCall *pc = 0;
dbus_send_ex(FINGERPRINT1_DBUS_SERVICE,
FINGERPRINT1_DBUS_ROOT_OBJECT,
FINGERPRINT1_DBUS_INTERFACE,
FINGERPRINT1_DBUS_REQ_ABORT,
fpoperation_abort_reply_cb,
self, 0,
&pc,
DBUS_TYPE_INVALID);
fpoperation_attach_pending_call(self, pc);
}
/* ========================================================================= *
* FPIDENTIFY
* ========================================================================= */
/** Identify operation - Hook for entering a state
*/
static void
fpidentify_enter_cb(fpoperation_t *self)
{
switch( fpoperation_state(self) ) {
case FPOPSTATE_INITIALIZE:
break;
case FPOPSTATE_WAITING:
break;
case FPOPSTATE_REQUEST:
fpoperation_start_identify(self);
break;
case FPOPSTATE_PENDING:
fpoperation_set_fpstate(self, FPSTATE_IDENTIFYING);
break;
case FPOPSTATE_SUCCESS:
/* We have identified fingerprint. Delay execution of fp wakeup
* briefly to see if some higher priority event such as power key
* press happens in close proximity, */
if( fpwakeup_set_primed(true) )
mce_log(LL_DEBUG, "fp wakeup primed");
fpoperation_attach_timeout(self, fingerprint_trigger_delay,
fpoperation_trigger_fpwakeup_cb);
break;
case FPOPSTATE_FAILURE:
break;
case FPOPSTATE_ABORT:
fpoperation_start_abort(self);
break;
case FPOPSTATE_ABORTING:
fpoperation_set_fpstate(self, FPSTATE_ABORTING);
break;
case FPOPSTATE_ABORTED:
break;
case FPOPSTATE_THROTTLING:
fpoperation_attach_timeout(self, fingerprint_throttle_delay,
fpoperation_throttling_ended_cb);
break;
default:
break;
}
}
/** Identify operation - Hook for leaving a state
*/
static void
fpidentify_leave_cb(fpoperation_t *self)
{
switch( fpoperation_state(self) ) {
case FPOPSTATE_INITIALIZE:
break;
case FPOPSTATE_WAITING:
break;
case FPOPSTATE_REQUEST:
fpoperation_cancel_pending_call(self);
break;
case FPOPSTATE_PENDING:
break;
case FPOPSTATE_SUCCESS:
break;
case FPOPSTATE_FAILURE:
break;
case FPOPSTATE_ABORT:
break;
case FPOPSTATE_ABORTING:
break;
case FPOPSTATE_ABORTED:
break;
case FPOPSTATE_THROTTLING:
fpoperation_cancel_timout(self);
break;
default:
break;
}
}
/** Identify operation - Hook for evaluating a state
*/
static void
fpidentify_eval_cb(fpoperation_t *self)
{
switch( fpoperation_state(self) ) {
case FPOPSTATE_INITIALIZE:
fpoperation_trans(self, FPOPSTATE_WAITING);
break;
case FPOPSTATE_WAITING:
if( !fpwakeup_is_allowed() )
break;
if( fpstate != FPSTATE_IDLE )
break;
fpoperation_trans(self, FPOPSTATE_REQUEST);
break;
case FPOPSTATE_REQUEST:
break;
case FPOPSTATE_PENDING:
if( !fpwakeup_is_allowed() ) {
fpoperation_trans(self, FPOPSTATE_ABORT);
}
else if( fpoperation_get_fpstate(self) != FPSTATE_IDENTIFYING ) {
fpoperation_trans(self, FPOPSTATE_FAILURE);
}
break;
case FPOPSTATE_ABORT:
break;
case FPOPSTATE_ABORTING:
switch( fpoperation_get_fpstate(self) ) {
case FPSTATE_ABORTING:
break;
case FPSTATE_IDLE:
fpoperation_trans(self, FPOPSTATE_ABORTED);
break;
default:
fpoperation_trans(self, FPOPSTATE_FAILURE);
break;
}
break;