一、Fingerprint上层总体架构

Fingerprint模块架构图如下,这里分为application,framework,fingerprintd和FingerprintHal这几个部分,不涉及指纹的IC库和驱动这部分,这部分逻辑由指纹厂商来实现,目前了解的并不多。 

二、Fingerprint framework初始化流程

在系统开机的时候,会启动各种Service,包括FingerprintService。从下图的开机log(sys_log.boot)中可以看出: 

FingerprintService的启动在SystemServer.Java的startOtherService方法中:

/*** Starts a miscellaneous grab bag of stuff that has yet to be refactored* and organized.*/private void startOtherServices() {final Context context = mSystemContext;VibratorService vibrator = null;IMountService mountService = null;.......//启动FingerprintServiceif (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {mSystemServiceManager.startService(FingerprintService.class);}......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

这里会通过PackageManager来判断是否支持指纹功能,这个判断是N新加的,如果支持的话,需要在framework/native/data/ect/目录下添加Android.hardware.fingerprint.xml来支持该功能,这样才能启动FingerprintService。 

这里启动的时候,会将FingerprintService添加到ServiceManager中去,如下图: 

将FingerprintService添加到ServiceManager中后,在SystemServiceRegistry.java中静态代码块中注册服务的时候,可以从ServiceManager中获取FingerprintService的Binder对象,从而可以构造出FingerprintManager对象,这样app端就可以通过Context来获取FingerprintManager对象。 

这样,app端通过Context获取FingerprintManager,通过调用FingerprintManager的接口来实现相应的功能,FingerprintManager转调FingerprintService中方法,FingerprintService负责管理整个注册,识别、删除指纹、检查权限等流程的逻辑,FingerprintService调用fingerprintd的接口,通过fingerprintd和FingerprintHal层进行通信。

在FingerprintService的getFingerprintDaemon方法中有如下步骤:

//①获取fingerprintd

//②向fingerprintd注册回调函数mDaemonCallback

//③调用获取fingerprintd的openhal函数

//④建立fingerprint文件系统节点,设置节点访问权限,调用fingerprintd的setActiveGroup,将路径传下去。此路径一半用来存储指纹模板的图片等

public IFingerprintDaemon getFingerprintDaemon() {if (mDaemon == null) {//①获取fingerprintdmDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD));if (mDaemon != null) {try {mDaemon.asBinder().linkToDeath(this, 0);//②向fingerprintd注册回调函数mDaemonCallbackmDaemon.init(mDaemonCallback);//③调用获取fingerprintd的openhal函数mHalDeviceId = mDaemon.openHal();/*④建立fingerprint文件系统节点,设置节点访问权限,调用fingerprintd的setActiveGroup,将路径传下去。此路径一半用来存储指纹模板的图片等*/if (mHalDeviceId != 0) {updateActiveGroup(ActivityManager.getCurrentUser());} else {Slog.w(TAG, "Failed to open Fingerprint HAL!");mDaemon = null;}} catch (RemoteException e) {Slog.e(TAG, "Failed to open fingeprintd HAL", e);mDaemon = null; // try again later!}} else {Slog.w(TAG, "fingerprint service not available");}}return mDaemon;}
  • 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
  • 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
1 FingerprintService在framework模块负责指纹的大部分逻辑,FingerprintService会在开机的时候初始化;
2 application调用framework通过FingerprintManager接口即可实现;
3 framework中FingerManager和FingerprintService的通信使用Binder机制实现,表现即使用aidl这个接口定义语言实现
4 framework调往fingerprintd的同样属于Binder通信,两者分属于不同的进程。不过这部分跟java层Binder处理有点不一样,是java层往native层的调用。

三、fingerprintd 部分的初始化

在system/core/fingerprintd目录下,有如下文件: 

fingerprintd如果划分的比较细的话,可以分为四个部分:
1.fingerprintd.cpp   "负责将fingerprintd加入到ServiceManager中,以便FingerprintService能够获取"
2.IFingerprintDaemon.h/IFingerprintDaemon.cpp  "负责java层到fingerprintd的Binder通信"
3.FingerprintDaemonProxy.h/FingerprintDaemonProxy.cpp  "负责fingerprintd和Fignerprint hal层的通信"
4.IFingerprintDaemonCallback.h/IFingerprintDaemonCallback.cpp "负责将指纹的回调结果传给java层"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
fingerprintd在init.rc有相应的开机启动脚本,所以一开机就会跑它的main函数。fingerprintd作为一个独立的进程运行,负责将Framework和Hal层的通信连接起来。

fingerprintd 的main函数就是将fingerprintd添加到servicemanager中管理。然后开了一个线程,等待binder消息。

四、接下来简单介绍下IFingerprintDaemon是如何跟framework通信的。

来看下IFingerprintDaemon.h文件:

17#ifndef IFINGERPRINT_DAEMON_H_
18#define IFINGERPRINT_DAEMON_H_
19
20#include <binder/IInterface.h>
21#include <binder/Parcel.h>
22
23namespace android {
24
25class IFingerprintDaemonCallback;
26
27/*
28* Abstract base class for native implementation of FingerprintService.
29*
30* Note: This must be kept manually in sync with IFingerprintDaemon.aidl
31*/
32class IFingerprintDaemon : public IInterface, public IBinder::DeathRecipient {
33    public:
34        enum {
35           AUTHENTICATE = IBinder::FIRST_CALL_TRANSACTION + 0,
36           CANCEL_AUTHENTICATION = IBinder::FIRST_CALL_TRANSACTION + 1,
37           ENROLL = IBinder::FIRST_CALL_TRANSACTION + 2,
38           CANCEL_ENROLLMENT = IBinder::FIRST_CALL_TRANSACTION + 3,
39           PRE_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 4,
40           REMOVE = IBinder::FIRST_CALL_TRANSACTION + 5,
41           GET_AUTHENTICATOR_ID = IBinder::FIRST_CALL_TRANSACTION + 6,
42           SET_ACTIVE_GROUP = IBinder::FIRST_CALL_TRANSACTION + 7,
43           OPEN_HAL = IBinder::FIRST_CALL_TRANSACTION + 8,
44           CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 9,
45           INIT = IBinder::FIRST_CALL_TRANSACTION + 10,
46           POST_ENROLL = IBinder::FIRST_CALL_TRANSACTION + 11,
47           ENUMERATE = IBinder::FIRST_CALL_TRANSACTION + 12,
48        };
49
50        IFingerprintDaemon() { }
51        virtual ~IFingerprintDaemon() { }
52        virtual const android::String16& getInterfaceDescriptor() const;
53
54        // Binder interface methods
55        virtual void init(const sp<IFingerprintDaemonCallback>& callback) = 0;
56        virtual int32_t enroll(const uint8_t* token, ssize_t tokenLength, int32_t groupId,
57                int32_t timeout) = 0;
58        virtual uint64_t preEnroll() = 0;
59        virtual int32_t postEnroll() = 0;
60        virtual int32_t stopEnrollment() = 0;
61        virtual int32_t authenticate(uint64_t sessionId, uint32_t groupId) = 0;
62        virtual int32_t stopAuthentication() = 0;
63        virtual int32_t remove(int32_t fingerId, int32_t groupId) = 0;
64        virtual int32_t enumerate() = 0;
65        virtual uint64_t getAuthenticatorId() = 0;
66        virtual int32_t setActiveGroup(int32_t groupId, const uint8_t* path, ssize_t pathLen) = 0;
67        virtual int64_t openHal() = 0;
68        virtual int32_t closeHal() = 0;
69
70        // DECLARE_META_INTERFACE - C++ client interface not needed
71        static const android::String16 descriptor;
72        static void hal_notify_callback(const fingerprint_msg_t *msg);
73};
74
75// ----------------------------------------------------------------------------
76
77class BnFingerprintDaemon: public BnInterface<IFingerprintDaemon> {
78    public:
79       virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
80               uint32_t flags = 0);
81    private:
82       bool checkPermission(const String16& permission);
83};
84
85} // namespace android
86
87#endif // IFINGERPRINT_DAEMON_H_
  • 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
  • 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

java层到fingerprintd的通信这里同样是采用binder方式,注意到上面IFingerprintDaemon.h第30行的NOTE,需要手动保证IFingerprintDaemon.h文件与IFingerprintDaemon.aidl文件一致,由于java层aidl文件编译时会自动编译成IFingerprintDaemon.java文件。

当添加接口来调用指纹底层暴露的接口,在IFingerprintDaemon.h文件中添加类似上面35行到68行的枚举,枚举的值需要与java层aidl自动生成的java文件中的枚举保持一致。另外还需要在上面68行处加上描述这些接口的纯虚函数(c++中的纯虚函数类似java的抽象方法,用于定义接口的规范,在C++中,一个具有纯虚函数的基类被称为抽象类)。

如下面截图对比,我们发现IFingerprintDaemon.cpp和java层aidl生成的IFingerprintDaemon.java在onTransact是基本一致的。这样我们也就明白了为什么上面说需要手动和IFingerprintDaemon.aidl保持同步了,这样方式类似我们平时在三方应用使用aidl文件,需要保持client端和server端aidl文件一致。

可以看到onTransact有四个参数
code , data ,replay , flags
code 是一个整形的唯一标识,用于区分执行哪个方法,客户端会传递此参数,告诉服务端执行哪个方法
data客户端传递过来的参数
replay服务器返回回去的值
flags标明是否有返回值,0为有(双向),1为没有(单向)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

IFingerprintDaemon.aidl文件生成的IFingerprintDaemon.java文件 

接着介绍下fingerprintd进程是如何和Fingerprint Hal层是如何传递数据的。

说到Hal层,即硬件抽象层,android系统为HAL层中的模块接口定义了规范,所有工作于HAL的模块必须按照这个规范来编写模块接口,否则将无法正常访问硬件。 

指纹的HAL层规范fingerprint.h在/hardware/libhardware/include/hardware/下可以看到。

我们注意到在fingerprint.h中定义了两个结构体,分别是fingerprint_device_t和fingerprint_module_t,如下图。 

fingerprint_device_t结构体,用于描述指纹硬件设备;fingerprint_module_t结构体,用于描述指纹硬件模块。在FingerprintDaemonProxy.cpp就是通过拿到fingerprint_device_t这个结构体来和Fingerprint HAL层通信的。

当需要添加接口调用指纹底层时,在这个fingerprint.h中同样需要添加函数指针,然后通过FingerprintDaemonProxy.cpp中拿到这个fingerprint_device_t来调用fingerprint.h中定义的函数指针,也就相当于调用指纹HAL层。

我们重点看一下它的openHal()函数。

openHal的方法这里主要看上面三个部分: 
- ①根据名称获取指纹hal层模块。hw_module这个一般由指纹芯片厂商根据 fingerprint.h实现,hw_get_module是由HAL框架提供的一个公用的函数,这个函数的主要功能是根据模块ID(module_id)去查找注册在当前系统中与id对应的硬件对象,然后载入(load)其相应的HAL层驱动模块的*so文件。 
- ②调用fingerprint_module_t的open函数 
- ③向hal层注册消息回调函数,主要回调 注册指纹进度,识别结果,错误信息等等 
- ④判断向hal层注册消息回调是否注册成功

目前关于指纹的上层流程大致就到这儿,指纹底层就不怎么介绍了,术业有专攻,和专业做指纹的还是有不少差距。

android开发中Fingerprint模块浅析相关推荐

  1. Android开发中无处不在的设计模式——动态代理模式

    继续更新设计模式系列.写这个模式的主要原因是近期看到了动态代理的代码. 先来回想一下前5个模式: - Android开发中无处不在的设计模式--单例模式 - Android开发中无处不在的设计模式-- ...

  2. android中的mvp模式怎么定义,详解MVP模式在Android开发中的应用

    一.MVP介绍 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Mode ...

  3. Android中layout目录的作用,Android 开发中layout下的子文件夹

    Android 开发中layout下的子文件夹 发布时间:2020-10-25 11:42:36 来源:脚本之家 阅读:71 作者:厚土火焰山 如果一个项目内有很多个界面,那么在layout下会有太多 ...

  4. 如何单独编译Android源代码中的模块

    第一次下载好Android源代码工程后,我们通常是在android源代码工程目录下执行make命令,经过漫长的等待之后,就可以得到Android系统镜像system.img了.以后如果我们修改了And ...

  5. Android开发中应避免的重大错误

    by Varun Barad 由Varun Barad Android开发中应避免的重大错误 (Critical mistakes to avoid in Android development) A ...

  6. android 4.4 禁止下拉,Android开发中禁止下拉式的实现技巧

    我们开发项目的时候,经常会看到禁止的情况,而Android开发中并没有直接调用的接口,下面是爱站技术频道小编就给大家介绍的Android开发中禁止下拉式的实现技巧,希望网友们喜欢! 分享给大家供大家参 ...

  7. 史上最全Android开发中100%会用到的开源框架整理(1/5)

    其实这个开源框架整理很久了,只是一直放在有道云笔记里面,笔者还有很多写得文章都放在有道云笔记里面,有时间都好好整理一下放出来,本篇文章也会不定期更新,由于整理的开源框架分类都有200多个,所有这次只将 ...

  8. Android开发中使用七牛云存储进行图片上传下载

    Android开发中的图片存储本来就是比较耗时耗地的事情,而使用第三方的七牛云,便可以很好的解决这些后顾之忧,最近我也是在学习七牛的SDK,将使用过程在这记录下来,方便以后使用. 先说一下七牛云的存储 ...

  9. 5 个 Android 开发中比较常见的内存泄漏问题及解决办法

    Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要再 ...

  10. Android开发中的Handler和多线程

    在Android开发中我们常常用到Handler这个类去处理消息队列中的消息,以下这个例子实现的是利用Handler传递一个消息给线程,线程运行run()方法去更新进度条的进度,以下是源代码: pub ...

最新文章

  1. SQL Server查询某字段在哪些表中
  2. Android界面开发问题总结
  3. c语言cin n1 n2,牛客等级之题N1 追债之旅 - N2 Rinne Loves Study(8.6场)
  4. 1074 Reversing Linked List (25 分)【难度: 一般 / 知识点: 链表】
  5. Java编程字符逆序输出_用JAVA编写一程序:从键盘输入多个字符串到程序中,并将它们按逆序输出在屏幕上。...
  6. MailBee.NET Objects发送电子邮件(SMTP)教程六:创建并发送带有附件的邮件
  7. 数据库开发 - 事务 死锁分析与解决
  8. Linux系统下文件与目录操作讲解
  9. 不同vlan同段IP通信
  10. python下载第三方库失败的解决办法
  11. SE_01 需求分析
  12. vb改变字形的代码是什么_VB怎么改变字体?
  13. 华为防火墙配置(防火墙NAT)
  14. XDOJ32角谷定理
  15. LOG_PATH_IS_UNDEFINED 解决
  16. 苹果7 无线流量连接不上网络连接服务器,iPhone7连不上wifi无线网的四种解决方法...
  17. SecureCRT的使用方法和技巧(二) 常用指令
  18. Word2Vec词向量模型代码
  19. 2018年内大892数据结构部分参考答案
  20. ipad发布会ipad_ipad十周年,从办公室的角度

热门文章

  1. codeforces 558D Guess Your Way Out! II 规律
  2. web前端压缩图片方法——加快页面加载速度
  3. 带左右箭头的图片轮播
  4. KEGG Orthology 数据库简介
  5. [处理方法]微信内置浏览器 打开页面空白
  6. php 自动生成考卷下载,试卷生成器下载-试卷生成器电脑版下载[试题生成]-华军软件园...
  7. linux 如何获取最高权限 设定
  8. Vb中 继承 多态的实现
  9. AI公司盈利难?MSN聊天机器人起家的小i是如何做到的
  10. 公众号开发入门:查询用户是否已经关注公众号?