Support removing a fingerprint

Support deleting a fingerprint based on ID rather than table index.
When deleting an entry, or deleting multiple entries via "delete all,"
send a notification of each ID that was deleted.

Change-Id: Ifd79f659fa6246ab3fecd86ee59a887b359e6168
diff --git a/fingerprint/fingerprint.c b/fingerprint/fingerprint.c
index c3dc787..97b6d73 100644
--- a/fingerprint/fingerprint.c
+++ b/fingerprint/fingerprint.c
@@ -14,11 +14,7 @@
  * limitations under the License.
  */
 
-#define  FINGERPRINT_LISTEN_SERVICE_NAME "fingerprintlisten"
-#define  FINGERPRINT_TXT_FILENAME "/data/fingerprint.txt"
-
 #define LOG_TAG "FingerprintHal"
-#define MAX_NUM_FINGERS 32
 
 #include <errno.h>
 #include <endian.h>
@@ -30,239 +26,145 @@
 #include <hardware/fingerprint.h>
 #include <hardware/qemud.h>
 
+#define FINGERPRINT_LISTEN_SERVICE_NAME "fingerprintlisten"
+#define FINGERPRINT_FILENAME \
+    "/data/system/users/0/fpdata/emulator_fingerprint_storage.bin"
+#define MAX_COMM_CHARS 128
+#define MAX_COMM_ERRORS 8
+#define MAX_NUM_FINGERS 20
+#define MAX_FID_VALUE 0x7FFFFFFF  // Arbitrary limit
+
 typedef enum worker_state_t {
-    STATE_ENROLL = 1,
-    STATE_SCAN = 2,
-    STATE_IDLE = 3,
-    STATE_EXIT = 4
+    STATE_IDLE = 0,
+    STATE_ENROLL,
+    STATE_SCAN,
+    STATE_EXIT
 } worker_state_t;
 
 typedef struct worker_thread_t {
     pthread_t thread;
-    pthread_mutex_t mutex;
-    int request;
     worker_state_t state;
-    int fingerid;
-    int finger_is_on;
-    int all_fingerids[MAX_NUM_FINGERS];
-    uint64_t all_secureids[MAX_NUM_FINGERS];
-    uint64_t all_authenids[MAX_NUM_FINGERS];
-    int num_fingers_enrolled;
-    FILE *fp_write;;
+    uint64_t secureid[MAX_NUM_FINGERS];
+    uint64_t authenid[MAX_NUM_FINGERS];
 } worker_thread_t;
 
-typedef struct emu_fingerprint_hal_device_t {
-    fingerprint_device_t device; //inheritance
+typedef struct qemu_fingerprint_device_t {
+    fingerprint_device_t device;  // "inheritance"
     worker_thread_t listener;
     uint64_t op_id;
     uint64_t challenge;
-    uint64_t secure_user_id;
     uint64_t user_id;
+    uint64_t group_id;
+    uint64_t secure_user_id;
     uint64_t authenticator_id;
+    int qchanfd;
     pthread_mutex_t lock;
-} emu_fingerprint_hal_device_t;
+} qemu_fingerprint_device_t;
+
+/******************************************************************************/
+
+static void saveFingerprint(worker_thread_t* listener, int idx) {
+    ALOGD("----------------> %s -----------------> idx %d", __FUNCTION__, idx);
+
+    // Save fingerprints to file
+    FILE* fp = fopen(FINGERPRINT_FILENAME, "r+");  // write but don't truncate
+    if (fp == NULL) {
+        ALOGE("Could not open fingerprints storage at %s; "
+              "fingerprints won't be saved",
+              FINGERPRINT_FILENAME);
+        perror("Failed to open file");
+        return;
+    }
+
+    ALOGD("Write fingerprint[%d] (0x%" PRIx64 ",0x%" PRIx64 ")", idx,
+          listener->secureid[idx], listener->authenid[idx]);
+
+    if (fseek(fp, (idx) * sizeof(uint64_t), SEEK_SET) < 0) {
+        ALOGE("Failed while seeking for fingerprint[%d] in emulator storage",
+              idx);
+        fclose(fp);
+        return;
+    }
+    int ns = fwrite(&listener->secureid[idx], sizeof(uint64_t), 1, fp);
+    if (fseek(fp, (MAX_NUM_FINGERS + idx) * sizeof(uint64_t), SEEK_SET) < 0) {
+        ALOGE("Failed while seeking for fingerprint[%d] in emulator storage",
+              idx);
+        fclose(fp);
+        return;
+    }
+    int na = fwrite(&listener->authenid[idx], sizeof(uint64_t), 1, fp);
+    if (ns != 1 || na != 1)
+        ALOGW("Corrupt emulator fingerprints storage; could not save "
+              "fingerprints");
+
+    fclose(fp);
+
+    return;
+}
+
+static void loadFingerprints(worker_thread_t* listener) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    FILE* fp = fopen(FINGERPRINT_FILENAME, "a+");  // so we can create if empty
+    if (fp == NULL) {
+        ALOGE("Could not load fingerprints from storage at %s; "
+              "it has not yet been created.",
+              FINGERPRINT_FILENAME);
+        perror("Failed to open/create file");
+        return;
+    }
+
+    int ns = fread(listener->secureid, MAX_NUM_FINGERS * sizeof(uint64_t), 1,
+                   fp);
+    int na = fread(listener->authenid, MAX_NUM_FINGERS * sizeof(uint64_t), 1,
+                   fp);
+    if (ns != 1 || na != 1)
+        ALOGW("Corrupt emulator fingerprints storage (read %d+%db)", ns, na);
+
+    int i = 0;
+    for (i = 0; i < MAX_NUM_FINGERS; i++)
+        ALOGD("Read fingerprint %d (0x%" PRIx64 ",0x%" PRIx64 ")", i,
+              listener->secureid[i], listener->authenid[i]);
+
+    fclose(fp);
+
+    return;
+}
+
+/******************************************************************************/
 
 static uint64_t get_64bit_rand() {
-    return (((uint64_t) rand()) << 32) | ((uint64_t) rand());
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    uint64_t r = (((uint64_t)rand()) << 32) | ((uint64_t)rand());
+    return r != 0 ? r : 1;
 }
 
-static void destroyListenerThread(emu_fingerprint_hal_device_t* dev)
-{
-    pthread_join(dev->listener.thread, NULL);
-    pthread_mutex_destroy(&dev->listener.mutex);
-}
+static uint64_t fingerprint_get_auth_id(struct fingerprint_device* device) {
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    uint64_t authenticator_id = 0;
+    pthread_mutex_lock(&qdev->lock);
+    authenticator_id = qdev->authenticator_id;
+    pthread_mutex_unlock(&qdev->lock);
 
-bool finger_already_enrolled(emu_fingerprint_hal_device_t* dev) {
-    int i;
-    for (i = 0; i < dev->listener.num_fingers_enrolled; ++ i) {
-        if (dev->listener.fingerid == dev->listener.all_fingerids[i % MAX_NUM_FINGERS]) {
-            dev->secure_user_id = dev->listener.all_secureids[i % MAX_NUM_FINGERS];
-            dev->authenticator_id = dev->listener.all_authenids[i % MAX_NUM_FINGERS];
-            return true;
-        }
-    }
-    return false;
-}
-
-static void save_fingerid(FILE* fp, int fingerid, uint64_t secureid, uint64_t authenid) {
-    if (!fp) return;
-    fprintf(fp, " %d %" PRIu64 " %" PRIu64, fingerid, secureid, authenid);
-    fflush(fp);
-}
-
-static void listener_send_notice(emu_fingerprint_hal_device_t* dev)
-{
-    fingerprint_msg_t message = {0};
-    bool is_authentication = false;
-    bool is_valid_finger = false;
-    pthread_mutex_lock(&dev->listener.mutex);
-    if (dev->listener.state == STATE_ENROLL) {
-        message.type = FINGERPRINT_TEMPLATE_ENROLLING;
-        message.data.enroll.finger.fid = dev->listener.fingerid;
-        message.data.enroll.samples_remaining = 0;
-        dev->authenticator_id = get_64bit_rand();
-        dev->listener.state = STATE_SCAN;
-        if (!finger_already_enrolled(dev)) {
-            dev->listener.all_fingerids[dev->listener.num_fingers_enrolled % MAX_NUM_FINGERS] = dev->listener.fingerid;
-            dev->listener.all_secureids[dev->listener.num_fingers_enrolled % MAX_NUM_FINGERS] = dev->secure_user_id;
-            dev->listener.all_authenids[dev->listener.num_fingers_enrolled % MAX_NUM_FINGERS] = dev->authenticator_id;
-            ++ dev->listener.num_fingers_enrolled;
-            save_fingerid(dev->listener.fp_write, dev->listener.fingerid, dev->secure_user_id, dev->authenticator_id);
-            is_valid_finger = true;
-        }
-    } else {
-        is_authentication = true;
-        is_valid_finger = finger_already_enrolled(dev);
-        message.type = FINGERPRINT_AUTHENTICATED;
-        message.data.authenticated.finger.gid = 0;
-        message.data.authenticated.finger.fid = is_valid_finger ? dev->listener.fingerid : 0;
-        message.data.authenticated.hat.version = HW_AUTH_TOKEN_VERSION;
-        message.data.authenticated.hat.authenticator_type = htobe32(HW_AUTH_FINGERPRINT);
-        message.data.authenticated.hat.challenge = dev->op_id;
-        message.data.authenticated.hat.authenticator_id = dev->authenticator_id;
-        message.data.authenticated.hat.user_id = dev->secure_user_id;
-        struct timespec ts;
-        clock_gettime(CLOCK_MONOTONIC, &ts);
-        message.data.authenticated.hat.timestamp =
-            htobe64((uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
-    }
-    pthread_mutex_unlock(&dev->listener.mutex);
-
-    pthread_mutex_lock(&dev->lock);
-    if (is_authentication) {
-        fingerprint_msg_t acquired_message = {0};
-        acquired_message.type = FINGERPRINT_ACQUIRED;
-        message.data.acquired.acquired_info = FINGERPRINT_ACQUIRED_GOOD;
-        dev->device.notify(&acquired_message);
-    }
-    if (is_valid_finger || is_authentication) {
-        dev->device.notify(&message);
-    }
-    pthread_mutex_unlock(&dev->lock);
-}
-
-static void* listenerFunction(void* data)
-{
-    emu_fingerprint_hal_device_t* dev = (emu_fingerprint_hal_device_t*) data;
-
-    int fd = qemud_channel_open(FINGERPRINT_LISTEN_SERVICE_NAME);
-    if (fd < 0) {
-        ALOGE("listener cannot open fingerprint listener service exit");
-        return NULL;
-    }
-
-    const char* cmd = "listen";
-    if (qemud_channel_send(fd, cmd, strlen(cmd)) < 0) {
-        ALOGE("cannot write fingerprint 'listen' to host");
-        return NULL;
-    }
-
-    int i;
-    for (i = 0; i < MAX_NUM_FINGERS; ++ i) {
-        dev->listener.all_fingerids[i] = 0;
-    }
-    //read registered fingerprint ids from /data/local/fingerprint.txt
-    //TODO: store it in a better location
-    dev->listener.num_fingers_enrolled = 0;
-    FILE* fp_stored = fopen(FINGERPRINT_TXT_FILENAME, "r");
-    if (fp_stored) {
-        while (1) {
-            int fingerid = 0;
-            uint64_t secureid = 0;
-            uint64_t authenid = 0;
-            if(fscanf(fp_stored, "%d %" SCNu64 " %" SCNu64, &fingerid, &secureid, &authenid) == 3) {
-                dev->listener.all_fingerids[dev->listener.num_fingers_enrolled % MAX_NUM_FINGERS] = fingerid;
-                dev->listener.all_secureids[dev->listener.num_fingers_enrolled % MAX_NUM_FINGERS] = secureid;
-                dev->listener.all_authenids[dev->listener.num_fingers_enrolled % MAX_NUM_FINGERS] = authenid;
-                ++ dev->listener.num_fingers_enrolled;
-            } else {
-                break;
-            }
-        }
-        fclose(fp_stored);
-    }
-
-    dev->listener.fp_write = fopen(FINGERPRINT_TXT_FILENAME, "a");
-
-    char buffer[128];
-    int fingerid=-1;
-    int size;
-    while (1) {
-        //simply listen in blocking mode
-        if ((size = qemud_channel_recv(fd, buffer, sizeof buffer - 1)) >0) {
-            buffer[size] = '\0';
-            if (sscanf(buffer, "on:%d", &fingerid) == 1) {
-                if (fingerid > 0 ) {
-                    dev->listener.fingerid = fingerid;
-                    dev->listener.finger_is_on = 1;
-                    ALOGD("got finger %d", fingerid);
-                    listener_send_notice(dev);
-                    ALOGD("send notice finger %d", fingerid);
-                }
-                else {
-                    ALOGE("finger id should be positive");
-                }
-            } else if (strncmp("off", buffer, 3) == 0) {
-                dev->listener.finger_is_on = 0;
-                ALOGD("finger off %d", fingerid);
-            } else {
-                ALOGE("error: '%s'", buffer);
-            }
-        } else {
-            ALOGE("receive failure");
-            // return NULL;
-        }
-        //TODO: check for request to exit thread
-    }
-
-    ALOGD("listener exit");
-    return NULL;
-}
-
-static void createListenerThread(emu_fingerprint_hal_device_t* dev)
-{
-    pthread_mutex_init(&dev->listener.mutex, NULL);
-    pthread_create(&dev->listener.thread, NULL, listenerFunction, dev);
-}
-
-static int fingerprint_close(hw_device_t *dev)
-{
-    if (dev) {
-        destroyListenerThread((emu_fingerprint_hal_device_t*) dev);
-        free(dev);
-        return 0;
-    } else {
-        return -1;
-    }
-}
-
-static void setListenerState(emu_fingerprint_hal_device_t* dev, worker_state_t state) {
-    pthread_mutex_lock(&dev->listener.mutex);
-    dev->listener.state = state;
-    pthread_mutex_unlock(&dev->listener.mutex);
-}
-
-static uint64_t fingerprint_get_auth_id(struct fingerprint_device __unused *device) {
-    emu_fingerprint_hal_device_t* dev = (emu_fingerprint_hal_device_t*) device;
-    return dev->authenticator_id;
+    return authenticator_id;
 }
 
 static int fingerprint_set_active_group(struct fingerprint_device __unused *device, uint32_t gid,
         const char *path) {
-    // TODO: implements me
+    ALOGW("Setting active finger group not implemented");
     return 0;
 }
 
-static int fingerprint_authenticate(struct fingerprint_device __unused *device,
-    uint64_t __unused operation_id, __unused uint32_t gid)
+static int fingerprint_authenticate(struct fingerprint_device *device,
+    uint64_t operation_id, __unused uint32_t gid)
 {
-    ALOGD("fingerprint_authenticate");
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
 
-    emu_fingerprint_hal_device_t* dev = (emu_fingerprint_hal_device_t*) device;
-    pthread_mutex_lock(&dev->lock);
-    dev->op_id = operation_id;
-    pthread_mutex_unlock(&dev->lock);
-    setListenerState(dev, STATE_SCAN);
+    pthread_mutex_lock(&qdev->lock);
+    qdev->op_id = operation_id;
+    qdev->listener.state = STATE_SCAN;
+    pthread_mutex_unlock(&qdev->lock);
+
     return 0;
 }
 
@@ -271,11 +173,15 @@
         uint32_t __unused gid,
         uint32_t __unused timeout_sec) {
     ALOGD("fingerprint_enroll");
-    emu_fingerprint_hal_device_t* dev = (emu_fingerprint_hal_device_t*) device;
-    if (hat && hat->challenge == dev->challenge) {
+    qemu_fingerprint_device_t* dev = (qemu_fingerprint_device_t*)device;
+    if (!hat) {
+        ALOGW("%s: null auth token", __func__);
+        return -EPROTONOSUPPORT;
+    }
+    if (hat->challenge == dev->challenge) {
         dev->secure_user_id = hat->user_id;
     } else {
-        ALOGW("%s: invalid or null auth token", __func__);
+        ALOGW("%s: invalid auth token", __func__);
     }
 
     if (hat->version != HW_AUTH_TOKEN_VERSION) {
@@ -287,81 +193,401 @@
 
     dev->user_id = hat->user_id;
 
-    // TODO: store enrolled fingerprints, authenticator id, and secure_user_id
-    setListenerState(dev, STATE_ENROLL);
+    pthread_mutex_lock(&dev->lock);
+    dev->listener.state = STATE_ENROLL;
+    pthread_mutex_unlock(&dev->lock);
+
+    // fingerprint id, authenticator id, and secure_user_id
+    // will be stored by worked thread
+
     return 0;
 
 }
 
 static uint64_t fingerprint_pre_enroll(struct fingerprint_device *device) {
-    ALOGD("fingerprint_pre_enroll");
-    emu_fingerprint_hal_device_t* dev = (emu_fingerprint_hal_device_t*) device;
-    dev->challenge = get_64bit_rand();
-    return dev->challenge;
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    uint64_t challenge = 0;
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+
+    challenge = get_64bit_rand();
+
+    pthread_mutex_lock(&qdev->lock);
+    qdev->challenge = challenge;
+    pthread_mutex_unlock(&qdev->lock);
+
+    return challenge;
 }
 
-static int fingerprint_cancel(struct fingerprint_device __unused *device) {
-    ALOGD("fingerprint_cancel");
-    emu_fingerprint_hal_device_t* dev = (emu_fingerprint_hal_device_t*) device;
-    setListenerState(dev, STATE_IDLE);
+static int fingerprint_post_enroll(struct fingerprint_device* device) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+
+    pthread_mutex_lock(&qdev->lock);
+    qdev->challenge = 0;
+    pthread_mutex_unlock(&qdev->lock);
+
+    return 0;
+}
+
+static int fingerprint_cancel(struct fingerprint_device *device) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+
+    fingerprint_msg_t msg = {0};
+    msg.type = FINGERPRINT_ERROR;
+    msg.data.error = FINGERPRINT_ERROR_CANCELED;
+
+    pthread_mutex_lock(&qdev->lock);
+    qdev->listener.state = STATE_IDLE;
+    pthread_mutex_unlock(&qdev->lock);
+
+    device->notify(&msg);
+
     return 0;
 }
 
 static int fingerprint_enumerate(struct fingerprint_device *device,
         fingerprint_finger_id_t *results, uint32_t *max_size) {
-    // TODO: implement me
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    if (device == NULL || results == NULL || max_size == NULL) {
+        ALOGE("Cannot enumerate saved fingerprints with uninitialized params");
+        return -1;
+    }
+
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+    unsigned int i = 0;
+    int num = 0;
+    for (i = 0; i < MAX_NUM_FINGERS; i++) {
+        if (qdev->listener.secureid[i] != 0 ||
+            qdev->listener.authenid[i] != 0) {
+            ALOGD("ENUM: Fingerprint [%d] = 0x%" PRIx64 ",%" PRIx64, i,
+                  qdev->listener.secureid[i], qdev->listener.authenid[i]);
+            num++;
+        }
+    }
+
+    return num;
+}
+
+static int fingerprint_remove(struct fingerprint_device *device,
+        uint32_t __unused gid, uint32_t fid) {
+    int idx = 0;
+    fingerprint_msg_t msg = {0};
+    ALOGD("----------------> %s -----------------> fid %d", __FUNCTION__, fid);
+    if (device == NULL) {
+        ALOGE("Can't remove fingerprint (gid=%d, fid=%d); "
+              "device not initialized properly",
+              gid, fid);
+        return -1;
+    }
+
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+
+    if (fid == 0) {
+        // Delete all fingerprints
+        // I'll do this one at a time, so I am not
+        // holding the mutext during the notification
+        bool listIsEmpty;
+        do {
+            pthread_mutex_lock(&qdev->lock);
+            listIsEmpty = true;  // Haven't seen a valid entry yet
+            for (idx = 0; idx < MAX_NUM_FINGERS; idx++) {
+                uint32_t theFid = qdev->listener.authenid[idx];
+                if (theFid != 0) {
+                    // Delete this entry
+                    qdev->listener.secureid[idx] = 0;
+                    qdev->listener.authenid[idx] = 0;
+                    saveFingerprint(&qdev->listener, idx);
+
+                    // Send a notification that we deleted this one
+                    pthread_mutex_unlock(&qdev->lock);
+                    msg.type = FINGERPRINT_TEMPLATE_REMOVED;
+                    msg.data.removed.finger.fid = theFid;
+                    device->notify(&msg);
+
+                    // Because we released the mutex, the list
+                    // may have changed. Restart the 'for' loop
+                    // after reacquiring the mutex.
+                    listIsEmpty = false;
+                    break;
+                }
+            }  // end for (idx < MAX_NUM_FINGERS)
+        } while (!listIsEmpty);
+        qdev->listener.state = STATE_IDLE;
+        pthread_mutex_unlock(&qdev->lock);
+    } else {
+        // Delete one fingerprint
+        // Look for this finger ID in our table.
+        pthread_mutex_lock(&qdev->lock);
+        for (idx = 0; idx < MAX_NUM_FINGERS; idx++) {
+            if (qdev->listener.authenid[idx] == fid &&
+                qdev->listener.secureid[idx] != 0) {
+                // Found it!
+                break;
+            }
+        }
+        if (idx >= MAX_NUM_FINGERS) {
+            qdev->listener.state = STATE_IDLE;
+            pthread_mutex_unlock(&qdev->lock);
+            ALOGE("Fingerprint ID %d not found", fid);
+            return FINGERPRINT_ERROR;
+        }
+
+        qdev->listener.secureid[idx] = 0;
+        qdev->listener.authenid[idx] = 0;
+        saveFingerprint(&qdev->listener, idx);
+
+        qdev->listener.state = STATE_IDLE;
+        pthread_mutex_unlock(&qdev->lock);
+
+        msg.type = FINGERPRINT_TEMPLATE_REMOVED;
+        msg.data.removed.finger.fid = fid;
+        device->notify(&msg);
+    }
+
     return 0;
 }
 
-static int fingerprint_remove(struct fingerprint_device __unused *dev,
-        uint32_t __unused gid, uint32_t __unused fid) {
-    // TODO: implement enroll and remove, and set dev->authenticator_id = 0 when no FPs enrolled
-    return FINGERPRINT_ERROR;
+static int set_notify_callback(struct fingerprint_device *device,
+                               fingerprint_notify_t notify) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    if (device == NULL || notify == NULL) {
+        ALOGE("Failed to set notify callback @ %p for fingerprint device %p",
+              device, notify);
+        return -1;
+    }
+
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+    pthread_mutex_lock(&qdev->lock);
+    qdev->listener.state = STATE_IDLE;
+    device->notify = notify;
+    pthread_mutex_unlock(&qdev->lock);
+    ALOGD("fingerprint callback notification set");
+
+    return 0;
 }
 
-static int set_notify_callback(struct fingerprint_device *device,
-                                fingerprint_notify_t notify) {
-    ALOGD("set_notify");
-    emu_fingerprint_hal_device_t* dev =(emu_fingerprint_hal_device_t*) device;
+static void send_scan_notice(qemu_fingerprint_device_t* qdev, int fid) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+
+    // acquired message
+    fingerprint_msg_t acqu_msg = {0};
+    acqu_msg.type = FINGERPRINT_ACQUIRED;
+    acqu_msg.data.acquired.acquired_info = FINGERPRINT_ACQUIRED_GOOD;
+
+    // authenticated message
+    fingerprint_msg_t auth_msg = {0};
+    auth_msg.type = FINGERPRINT_AUTHENTICATED;
+    auth_msg.data.authenticated.finger.fid = fid;
+    auth_msg.data.authenticated.finger.gid = 0;  // unused
+    auth_msg.data.authenticated.hat.version = HW_AUTH_TOKEN_VERSION;
+    auth_msg.data.authenticated.hat.authenticator_type =
+            htobe32(HW_AUTH_FINGERPRINT);
+    auth_msg.data.authenticated.hat.challenge = qdev->op_id;
+    auth_msg.data.authenticated.hat.authenticator_id = qdev->authenticator_id;
+    auth_msg.data.authenticated.hat.user_id = qdev->secure_user_id;
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    auth_msg.data.authenticated.hat.timestamp =
+            htobe64((uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
+
+    //  pthread_mutex_lock(&qdev->lock);
+    qdev->device.notify(&acqu_msg);
+    qdev->device.notify(&auth_msg);
+    //  pthread_mutex_unlock(&qdev->lock);
+
+    return;
+}
+
+static void send_enroll_notice(qemu_fingerprint_device_t* qdev, int fid) {
+    ALOGD("----------------> %s -----------------> fid %d", __FUNCTION__, fid);
+
+    if (fid == 0) {
+        ALOGD("Fingerprint ID is zero (invalid)");
+        return;
+    }
+    if (qdev->secure_user_id == 0) {
+        ALOGD("Secure user ID is zero (invalid)");
+        return;
+    }
+
+    // Find an available entry in the table
+    pthread_mutex_lock(&qdev->lock);
+    int idx = 0;
+    for (idx = 0; idx < MAX_NUM_FINGERS; idx++) {
+        if (qdev->listener.secureid[idx] == 0 ||
+            qdev->listener.authenid[idx] == 0) {
+            // This entry is available
+            break;
+        }
+    }
+    if (idx >= MAX_NUM_FINGERS) {
+        qdev->listener.state = STATE_SCAN;
+        pthread_mutex_unlock(&qdev->lock);
+        ALOGD("Fingerprint ID table is full");
+        return;
+    }
+
+    qdev->listener.secureid[idx] = qdev->secure_user_id;
+    qdev->listener.authenid[idx] = fid;
+    saveFingerprint(&qdev->listener, idx);
+
+    qdev->listener.state = STATE_SCAN;
+    pthread_mutex_unlock(&qdev->lock);
+
+    // LOCKED notification?
+    fingerprint_msg_t msg = {0};
+    msg.type = FINGERPRINT_TEMPLATE_ENROLLING;
+    msg.data.enroll.finger.fid = fid;
+    msg.data.enroll.samples_remaining = 0;
+    qdev->device.notify(&msg);
+
+    return;
+}
+
+static worker_state_t getListenerState(qemu_fingerprint_device_t* dev) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    worker_state_t state = STATE_IDLE;
+
     pthread_mutex_lock(&dev->lock);
-    device->notify = notify;
+    state = dev->listener.state;
     pthread_mutex_unlock(&dev->lock);
+
+    return state;
+}
+
+static void* listenerFunction(void* data) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)data;
+
+    pthread_mutex_lock(&qdev->lock);
+    qdev->qchanfd = qemud_channel_open(FINGERPRINT_LISTEN_SERVICE_NAME);
+    if (qdev->qchanfd < 0) {
+        ALOGE("listener cannot open fingerprint listener service exit");
+        pthread_mutex_unlock(&qdev->lock);
+        return NULL;
+    }
+    qdev->listener.state = STATE_IDLE;
+    pthread_mutex_unlock(&qdev->lock);
+
+    const char* cmd = "listen";
+    if (qemud_channel_send(qdev->qchanfd, cmd, strlen(cmd)) < 0) {
+        ALOGE("cannot write fingerprint 'listen' to host");
+        return NULL;
+    }
+    int comm_errors = 0;
+    while (getListenerState(qdev) != STATE_EXIT) {
+        int size = 0;
+        int fid = 0;
+        char buffer[MAX_COMM_CHARS] = {0};
+        // will block until a new event happens
+        if ((size = qemud_channel_recv(qdev->qchanfd, buffer,
+                                       sizeof(buffer) - 1)) > 0) {
+            buffer[size] = '\0';
+            if (sscanf(buffer, "on:%d", &fid) == 1) {
+                if (fid > 0 && fid <= MAX_FID_VALUE) {
+                    switch (qdev->listener.state) {
+                        case STATE_ENROLL:
+                            send_enroll_notice(qdev, fid);
+                            break;
+                        case STATE_SCAN:
+                            send_scan_notice(qdev, fid);
+                            break;
+                        default:
+                            ALOGE("fingerprint event listener at unexpected "
+                                  "state 0%x",
+                                  qdev->listener.state);
+                    }
+                } else {
+                    ALOGE("fingerprintid %d not in valid range [%d, %d] and "
+                          "will be "
+                          "ignored",
+                          fid, 1, MAX_FID_VALUE);
+                    continue;
+                }
+            } else if (strncmp("off", buffer, 3) == 0) {
+                // TODO: Nothing to do here ? Looks valid
+                ALOGD("fingerprint ID %d off", fid);
+            } else {
+                ALOGE("Invalid command '%s' to fingerprint listener", buffer);
+            }
+        } else {
+            ALOGE("fingerprint listener receive failure");
+            if (comm_errors > MAX_COMM_ERRORS)
+                break;
+        }
+    }
+
+    ALOGD("Listener exit with %d receive errors", comm_errors);
+    return NULL;
+}
+
+static int fingerprint_close(hw_device_t* device) {
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
+    if (device == NULL) {
+        ALOGE("fingerprint hw device is NULL");
+        return -1;
+    }
+
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)device;
+    pthread_mutex_lock(&qdev->lock);
+    if (qdev->qchanfd != 0)
+        close(qdev->qchanfd);  // unblock listener
+    qdev->listener.state = STATE_EXIT;
+    pthread_mutex_unlock(&qdev->lock);
+
+    pthread_join(qdev->listener.thread, NULL);
+    pthread_mutex_destroy(&qdev->lock);
+    free(qdev);
+
     return 0;
 }
 
 static int fingerprint_open(const hw_module_t* module, const char __unused *id,
                             hw_device_t** device)
 {
+
+    ALOGD("----------------> %s ----------------->", __FUNCTION__);
     if (device == NULL) {
         ALOGE("NULL device on open");
         return -EINVAL;
-    } else {
-        ALOGD("fingerprint open\n");
     }
 
-    emu_fingerprint_hal_device_t *dev = malloc(sizeof(emu_fingerprint_hal_device_t));
-    memset(dev, 0, sizeof(emu_fingerprint_hal_device_t));
+    qemu_fingerprint_device_t* qdev = (qemu_fingerprint_device_t*)calloc(
+            1, sizeof(qemu_fingerprint_device_t));
+    if (qdev == NULL) {
+        ALOGE("Insufficient memory for virtual fingerprint device");
+        return -ENOMEM;
+    }
 
-    dev->device.common.tag = HARDWARE_DEVICE_TAG;
-    dev->device.common.version = HARDWARE_MODULE_API_VERSION(2, 0);
-    dev->device.common.module = (struct hw_module_t*) module;
-    dev->device.common.close = fingerprint_close;
-    dev->device.pre_enroll = fingerprint_pre_enroll;
-    dev->device.enroll = fingerprint_enroll;
-    dev->device.get_authenticator_id = fingerprint_get_auth_id;
-    dev->device.set_active_group = fingerprint_set_active_group;
-    dev->device.authenticate = fingerprint_authenticate;
-    dev->device.cancel = fingerprint_cancel;
-    dev->device.enumerate = fingerprint_enumerate;
-    dev->device.remove = fingerprint_remove;
-    dev->device.set_notify = set_notify_callback;
-    dev->device.notify = NULL;
+    loadFingerprints(&qdev->listener);
 
-    dev->authenticator_id = 0xdeadbeef;
+    qdev->device.common.tag = HARDWARE_DEVICE_TAG;
+    qdev->device.common.version = HARDWARE_MODULE_API_VERSION(2, 0);
+    qdev->device.common.module = (struct hw_module_t*)module;
+    qdev->device.common.close = fingerprint_close;
 
-    pthread_mutex_init(&dev->lock, NULL);
-    createListenerThread(dev);
-    *device = (hw_device_t*) dev;
+    qdev->device.pre_enroll = fingerprint_pre_enroll;
+    qdev->device.enroll = fingerprint_enroll;
+    qdev->device.post_enroll = fingerprint_post_enroll;
+    qdev->device.get_authenticator_id = fingerprint_get_auth_id;
+    qdev->device.set_active_group = fingerprint_set_active_group;
+    qdev->device.authenticate = fingerprint_authenticate;
+    qdev->device.cancel = fingerprint_cancel;
+    qdev->device.enumerate = fingerprint_enumerate;
+    qdev->device.remove = fingerprint_remove;
+    qdev->device.set_notify = set_notify_callback;
+    qdev->device.notify = NULL;
+
+    // init and create listener thread
+    pthread_mutex_init(&qdev->lock, NULL);
+    if (pthread_create(&qdev->listener.thread, NULL, listenerFunction, qdev) !=
+        0)
+        return -1;
+
+    // "Inheritance" / casting
+    *device = &qdev->device.common;
+
     return 0;
 }