biod
(Biometrics Daemon) is a daemon for enrolling, authenticating and
managing biometrics data for faster unlocking. It manages all biometric sensors
for all users of the device.
[TOC]
Record: specific piece of biometric data that a user registers along with its metadata.
Enroll: the act of registering a record.
EnrollSession: the session during which enrolling of a record happens.
Authenticate: the act of checking a new piece of biometric data against stored records.
AuthSession: the session during which authenticating a new piece of biometric data against stored records happens.
BiometricsManager: manager for a piece of device/hardware/sensor for
collecting a specific type of biometric data. Each BiometricsManager
is in
charge of storing the records that it enrolled.
For more context, see the Chromium OS Developer Guide.
-
Start working on the
biod
package:(chroot) $ cros_workon-<board> start biod
-
Build
biod
:(chroot) $ emerge-<board> biod
-
Deploy
biod
to yourDUT
:(chroot) $ cros deploy ${DUT_IP_ADDR} biod
As a shortcut, you can also
scp
thebiod
binary to your DUT.
biod
is controlled by upstart
.
(dut)$ start biod
(dut)$ stop biod
(dut)$ status biod
biod
's logs are written to /var/log/biod/biod.LATEST
.
The unit tests can be run with with the following command:
(chroot)$ FEATURES=test emerge-<board> biod
The records are stored under the directory:
/home/root/[hash_of_user_id]/biod/[name_of_biometrics_manager]/
with the file
name: Record[UUID]
.
UUID has the form of XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX
where X
represents
a lowercase hex digit. UUID is a 128-bit random number generated with guid
, so
it is highly unlikely to repeat. _
are used instead of -
because this UUID
is used in biod D-bus object paths, which do not allow -
.
Each record file is stored in JSON format, and contains one record and its record id and label.
The bio_fw_updater
tool is responsible for updating the FPMCU firmware
automatically on boot. The updater checks to see if the firmware binary in
/opt/google/biod/fw
matches the firmware that is flashed on the FPMCU and
performs an update if the two do not match. Note that it does not consider
whether the version of the firmware is semantically "newer"; it's strictly
checking for an exact version match.
To disable the automatic update, you can create the
.disable_fp_updater
file:
(dut) $ touch /opt/google/biod/fw/.disable_fp_updater
When hardware and software write protect for the FPMCU are enabled,
bio_fw_updater
will only update the RW portion of the firmware.
When devices are still under development, they will generally have
hardware write protect enabled, but not software write protect. In this mode,
bio_fw_updater
will update both RO and RW.
You can learn more about write protection and how to enable/disable in the Firmware Write Protection documentation.
bio_fw_updater
's logs are written to:
/var/log/biod/bio_fw_updater.LATEST
/var/log/biod/bio_fw_updater.PREVIOUS
/var/log/biod/bio_fw_updater.<TIMESTAMP>
/var/log/bio_fw_updater.out
CrosFpBiometric (fingerprint MCU) runs the firmware for image capture, matching
and enrollment. Biod (cros_fp_biometrics_manager.cc
) interacts with the MCU
by doing system calls on /dev/cros_fp
.
On receiving an Authentication request, biod makes a ioctl call to put the MCU in FP_MODE_MATCH. It then listens for MBKP events from the MCU. On receiving the event, based on the result, biod either reports success or failure to the D-bus client (typically Chrome).
Things get little complicated on devices with fingerprint overlapped on
power button. On these devices, we need to be careful not to interpret user's
interaction with power button as an intent to authenticate via fingerprint. To
avoid such scenarios, we ignore fingerprint matches if we have seen a power
button event in last few milliseconds. To achieve this, biod keeps track of
power button events (power_button_filter.cc
) by listening to d-bus events
advertised by powerd (power_manager.cc
). The sequence diagram below gives a
sequence of events on devices with fingerprint overlapped on power button.
*** note TODO
Biod communicates with Chrome via D-bus messages. Chrome provides the graphical interface for users to enroll new biometric data and manage their own records. Chrome is also responsible for the visual display during authentication.
When a user logs in or biod starts, biod will ask login manager for a list of currently logged-in users, and load from storage the records of the newly logged-in users.
When a user logs out, all users log out at the same time, biod receives a signal from login manager and remove all records in the memory.
Because the records are stored in per user stateful under
/home/root/[hash_of_user_id]
, they are naturally encrypted by cryptohome.
Records are encrypted when the users log out and decrypted when the users log
in. Cryptohome provides a layer of security to biod.
biod_client_tool
provides the interface to fake the behavior of a biometrics
client, for example, a lock screen or a biometric enrollment app. It can be used
to test biod and biometric sensors. Use the --help
flag to see the options.
Service Name: org.chromium.BiometricsDaemon
Root Object: /org/chromium/BiometricsDaemon
The root object implements the org.freedesktop.DBus.ObjectManager
interface
which should be used to enumerate the available biometric devices. Each
biometric device implements the
org.chromium.BiometricsDaemon.BiometricsManager
interface, which is used to
retrieve previously made records or to start an Enroll
or Authenticate
session. Enroll
sessions are for making new records. Authenticate
sessions
are for authenticating scanned biometric data against those previously made
records. Each session object can be used to end the session, but signals still
go through the BiometricsManager object to avoid a race condition between
starting a session and connecting to the session's signals. Something to note
about the session objects is that they will automatically be ended when the
D-Bus client that created them (whomever called StartEnrollSession
or
StartAuthSession
). This is to prevent the BiometricsManager
from entering a
stuck state in case the client crashes and nobody comes around to end the
session. This shouldn't be an issue unless one expects the session to continue
after the D-Bus client disconnects, for example while testing out biod
using
dbus-send
or other single shot command line dbus tool. Each
BiometricsManager
can have only one session running concurrently.
StartEnrollSession(in STRING user_id, in STRING label, out OBJECTPATH enroll_session)
-
user_id
refers to the sanitized user name returned by SanitizeUserName in libbrillo. -
label
is an arbitrary string chosen to be human readable by the user. -
The returned
enroll_session
object path implements theorg.chromium.BiometricsDaemon.EnrollSession
interface, butEnrollScanDone
andSessionFailed
signals still come from thisBiometricsManager
.
GetRecords(out ARRAY<OBJECTPATH> records)
Each returned object path implements the org.chromium.BiometricsDaemon.Record
interface.
DestroyAllRecords()
StartAuthSession(out OBJECTPATH auth_session)
The returned object path implements the
org.chromium.BiometricsDaemon.AuthSession
interface, but AuthScanDone
and
SessionFailed
signals still come from this BiometricsManager
.
EnrollScanDone(UINT32 scan_result, BOOL complete)
If complete
is true, the enrollment was successfully finished and saved.
The UINT32 scan_result
values are meant to be instructions to the user on how
to get a better scan. They are as follows:
Note: Pretty much ripped off from AOSP's fingerprint_acquired_info
in
fingerprint.h.
- 0 = Success (the sensor captured good data)
- 1 = Partial (sensor needs more data)
- 2 = Insufficient (too little detail for recognition)
- 3 = Sensor Dirty
- 4 = Too Slow (tell user to speed up)
- 5 = Too Fast (tell user to slow down)
- 6 = Immobile (tell user to move a little to get more data)
AuthScanDone(UINT32 scan_result, std::unordered_map<std::string, std::vector<std::string>> matches)
The returned matches
are a map from user id to a list of biometric record ids.
The user ids are the same ones given to StartEnrollSession
in previous enroll
sessions. Each user in the list have one or more records that indicate a match.
Note that a piece of biometric data could be registered multiple times under the
same or different users.
SessionFailed()
General failure of enroll session and/or authenticate session that can not be recovered from
UINT32 Type
Type
has one of the following values:
- 0 = Unknown
- 1 = Fingerprint
End()
Ends the authentication session and destroys this object path. Generally, the client should call this at some point because authentication sessions do not end on their own, unless there is some error.
Cancel()
Ends the enroll session without storing the enrollment and destroys this object path. Generally, the client should not call this as the Enroll session will end automatically once enough data is collected. Exceptions to this rule being that there was some error on the client side, the user explicitly canceled the session, or the client has determined the user to have given up, perhaps after some timeout has elapsed.
Remove()
Deletes this record object from memory and persistent storage. It will no longer participate in any future Authenticate sessions.
SetLabel(in STRING label)
Sets the human readable label of this Record
object.
STRING Label
Read-only property that gets the previously set (by either StartEnrollSession
or SetLabel
) human readable label of this record object.
The symbol <-
means Chrome sends the command to
org.chromium.BiometricsDaemon
The symbol ->
is either a response or a signal from
org.chromium.BiometricsDaemon
-
Logged in user clicks enroll in UI:
<- Object:/org/chromium/BiometricsDaemon Method:org.freedesktop.DBus.ObjectManager.GetManagedObjects -> [ "/org/chromium/BiometricsDaemon/BiometricsManager0" ] <- Object:/org/chromium/BiometricsDaemon/BiometricsManager0 Method:org.chromium.BiometricsDaemon.BiometricsManager.StartEnrollSession "<user id hash>" "Data 1" -> "/org/chromium/BiometricsDaemon/BiometricsManager0/EnrollSession"
-
User presses finger onto sensor
-> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Success) false
-
Chrome UI shows encouraging message about that scan to user
-
User presses finger again but too quickly
-> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Too Fast) false
-
Chrome UI shows a stern message about how the user's finger is too fast.
-
[...] Continued until biod determines there is enough data
-> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Success) true
-
Chrome displays successful enrollment message
-
Logged in user locks screen
<- Object:/org/chromium/BiometricsDaemon/BiometricsManager0 Method:org.chromium.BiometricsDaemon.BiometricsManager.StartAuthSession -> /org/chromium/BiometricsDaemon/BiometricsManager0/AuthSession
-
User does a scan with dirty sensor and lock screen informs the user of this
-> org.chromium.BiometricsDaemon.BiometricsManager.AuthScanDone (Sensor Dirty) [empty array]
-
User cleans sensor and tries again with success
-> org.chromium.BiometricsDaemon.BiometricsManager.AuthScanDone (Success) ["unordered_map<string user_id, vector<string record_id>>"]
-
Lock screen lets user in