Fingerprint Hal层分析

一前言

前面一片文章,介绍了Android Fingerprint的启动流程,只要是Fingerprintd跟FingerprintService的启动流程,阅读本篇文章之前,最好看下上篇文章Android Fingerprint完全解析(二) :Fingerprint启动流程

一.Android 含有硬件抽象层的框架图

二.Android 硬件抽象层简介

    Android系统的硬件抽象层(Hardware Abstract Layer,HAL)运行在用户空间内,它向下屏蔽硬件驱动模块的实现细节,向上提供硬件访问服务(JNI或者Binder)。通过硬件抽象层,Android 系统分两层来支持硬件设备,其中一层实现在用户空间,另一层实现在内核空间中。传统的Linux 系统把对硬件的支持完全实现在内核空间中,即把对硬件的支持完全实现在硬件驱动模块中。

    Android系统为什么要把对硬件的支持划分为两层来实现呢?我们知道,一方面,Linux内核源代码是遵循GPL协议的,即如果我们在Android系统所使用的Linux内核中添加或者修改了代码,那么就必须将它们公开。因此,如果Android 系统像其他的Linux系统一样,把对硬件的支持完全实现在硬件驱动模块中,那么就必须将这些硬件驱动模块源代码公开,这样就可能损害移动厂商的利益,因为这相当于暴露了硬件的实现细节和参数。另一方面,Android系统源代码是遵循Apache License 协议的,它允许移动设备厂商添加或者修改Android系统源代码,而又不必公开这些代码。因此,如果把对硬件的支持完全实现在Android系统的用户空间中,那么就可以隐藏硬件的实现细节和参数。然而,这是无法做到,因为只有在内核空间才有特权操作硬件设备。一个折中的解决方案便是将对硬件的支持分别实现在内核空间和用户空间中,其中,内核空间仍然是以硬件驱动模块的形式来支持,不过它只提供简单的硬件访问通道;而用户空间以硬件抽象层模块的形式来支持,它封装了硬件的实现细节跟参数。这样就可以保护移动设备厂商的利益了。

    ———————以上来自罗升阳的《Android系统源代码情景分析》

三.Android硬件抽象层模块的开发

1.Android硬件抽象层模块编写规范

  Android系统的硬件抽象层以模块的形式来管理各个硬件访问接口。每一个硬件模块都对应有一个动态链接库.so文件,这些动态链接库的编写需要符合一定的规范,否则不能正常运行。在Android 系统内部,每一个硬件抽象层模块都使用结构体hw_module_t 来描述,二硬件设备则使用结构体hw_device_t来描述。

  硬件抽象层模块文件定义在hardware/libhardware/hardware.c 文件中,

/**
* There are a set of variant filename for modules. The form of the filename
* is "<MODULE_ID>.variant.so" so for the led module the Dream variants
* of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
*
* led.trout.so
* led.msm7k.so
* led.ARMV6.so
* led.default.so
*/static const char *variant_keys[] = {
"ro.hardware",  /* This goes first so that it can pick up a differentfile on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch",
"ro.btstack"
};

  硬件抽象层模块文件命名规范是

hardware/libhardware/include/hardware/hardware.h

struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;/*** Every hardware module must have a data structure named HAL_MODULE_INFO_SYM* and the fields of this data structure must begin with hw_module_t*followed by module specific information.*/typedef struct hw_module_t {/** tag must be initialized to HARDWARE_MODULE_TAG */uint32_t tag;/*** The API version of the implemented module. The module owner is* responsible for updating the version when a module interface has* changed.** The derived modules such as gralloc and audio own and manage this field.* The module user must interpret the version field to decide whether or* not to inter-operate with the supplied module implementation.* For example, SurfaceFlinger is responsible for making sure that* it knows how to manage different versions of the gralloc-module API,* and AudioFlinger must know how to do the same for audio-module API.** The module API version should include a major and a minor component.* For example, version 1.0 could be represented as 0x0100. This format* implies that versions 0x0100-0x01ff are all API-compatible.** In the future, libhardware will expose a hw_get_module_version()* (or equivalent) function that will take minimum/maximum supported* versions as arguments and would be able to reject modules with* versions outside of the supplied range.*/uint16_t module_api_version;
#define version_major module_api_version/*** version_major/version_minor defines are supplied here for temporary* source code compatibility. They will be removed in the next version.* ALL clients must convert to the new version format.*//*** The API version of the HAL module interface. This is meant to* version the hw_module_t, hw_module_methods_t, and hw_device_t* structures and definitions.** The HAL interface owns this field. Module users/implementations* must NOT rely on this value for version information.** Presently, 0 is the only valid value.*/uint16_t hal_api_version;
#define version_minor hal_api_version/** Identifier of module */const char *id;/** Name of this module */const char *name;/** Author/owner/implementor of the module */const char *author;/** Modules methods */struct hw_module_methods_t* methods;/** module's dso */void* dso;#ifdef __LP64__uint64_t reserved[32-7];
#else/** padding to 128 bytes, reserved for future use */uint32_t reserved[32-7];
#endif} hw_module_t;/**
* Name of the hal_module_info
*/
#define HAL_MODULE_INFO_SYM         HMI/**
* Name of the hal_module_info as a string
*/
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"

注意点:

看hw_module_t的定义前面有一段注释,意思是,每个硬件模块都必须有一个名为HAL_MODULE_INFO_SYM的数据结构并且此数据结构的字段必须以hw_module_t开头后跟模块具体信息。

1.Android硬件抽象层模块加载过程

int64_t FingerprintDaemonProxy::openHal() {ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");int err;const hw_module_t *hw_module = NULL;if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {ALOGE("Can't open fingerprint HW Module, error: %d", err);return 0;}if (NULL == hw_module) {ALOGE("No valid fingerprint module");return 0;}......
}

上面就是fingerprintd打开指纹Hal层的地方,openHal()函数,其中hw_get_module()就是加载硬件抽象模块的地方

int hw_get_module(const char *id, const struct hw_module_t **module)
{return hw_get_module_by_class(id, NULL, module);
}int hw_get_module_by_class(const char *class_id, const char *inst,const struct hw_module_t **module)
{int i = 0;char prop[PATH_MAX] = {0};char path[PATH_MAX] = {0};char name[PATH_MAX] = {0};char prop_name[PATH_MAX] = {0};if (inst)snprintf(name, PATH_MAX, "%s.%s", class_id, inst);elsestrlcpy(name, class_id, PATH_MAX);snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);if (property_get(prop_name, prop, NULL) > 0) {if (hw_module_exists(path, sizeof(path), name, prop) == 0) {goto found;}}/* Loop through the configuration variants looking for a module */for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {if (property_get(variant_keys[i], prop, NULL) == 0) {continue;}if (hw_module_exists(path, sizeof(path), name, prop) == 0) {goto found;}}/* Nothing found, try the default */
if (hw_module_exists(path, sizeof(path), name, "default") == 0) {goto found;
}return -ENOENT;found:/* load the module, if this fails, we're doomed, and we should not try* to load a different variant. */return load(class_id, path, module);
}static int hw_module_exists(char *path, size_t path_len, const char *name,const char *subname)
{snprintf(path, path_len, "%s/%s.%s.so",HAL_LIBRARY_PATH2, name, subname);if (access(path, R_OK) == 0)return 0;snprintf(path, path_len, "%s/%s.%s.so",HAL_LIBRARY_PATH1, name, subname);if (access(path, R_OK) == 0)return 0;return -ENOENT;
}

   hw_get_module() 会调用hw_get_module_by_class函数,首先通过property_get 函数获取系统属性”ro.hardware”的值,如果找到,则通过hw_module_exists 函数去查找.so 文件存不存在。如果存在,直接加载;不存在,就再继续查找variant_keys 数组中,其他的系统属性值存不存在。如果存在,直接加载,不存在,则最后去加载

四.Android 6.0版本Fingerprint Hal层分析

  1. 在上文中提到,在系统启动过程中,Fingerprintd 会调用hw_get_module 函数来获取来加载指纹硬件抽象层模块文件.so文件。
  2. fingerprintd加载指纹模块成功之后,会得到了相应的fingerprint_module_t,之后就会去调用它的open函数,在这里实现fingerprint.h 定义的接口。然后赋值给device,fingerprintd 就能够用这个device 操纵hal的指纹模块了。一般也在这个地方,进行一些初始化操作。

    static int fingerprint_open(const hw_module_t* module, const char __unused *id, 
    hw_device_t** device) 

    if (device == NULL) { 
    ALOGE(“NULL device on open”); 
    return -EINVAL; 
    }

    fingerprint_device_t *dev = malloc(sizeof(fingerprint_device_t));
    memset(dev, 0, sizeof(fingerprint_device_t));dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = FINGERPRINT_MODULE_API_VERSION_2_0;
    dev->common.module = (struct hw_module_t*) module;
    dev->common.close = fingerprint_close;dev->pre_enroll = fingerprint_pre_enroll;
    dev->enroll = fingerprint_enroll;
    dev->get_authenticator_id = fingerprint_get_auth_id;
    dev->cancel = fingerprint_cancel;
    dev->remove = fingerprint_remove;
    dev->set_active_group = fingerprint_set_active_group;
    dev->authenticate = fingerprint_authenticate;
    dev->set_notify = set_notify_callback;
    dev->notify = NULL;*device = (hw_device_t*) dev;
    return 0;
    

    }

    fingerprint_module_t HAL_MODULE_INFO_SYM = { 
    .common = { 
    .tag = HARDWARE_MODULE_TAG, 
    .module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0, 
    .hal_api_version = HARDWARE_HAL_API_VERSION, 
    .id = FINGERPRINT_HARDWARE_MODULE_ID, 
    .name = “Demo Fingerprint HAL”, 
    .author = “The Android Open Source Project”, 
    .methods = &fingerprint_module_methods, 
    }, 
    };

在硬件抽象层的加载过程中,会对id 进行验证,这个id比较重要,不能轻易修改。

hardware/libhardware/include/hardware/fingerprint.h

/* Callback function type */
typedef void (*fingerprint_notify_t)(const fingerprint_msg_t *msg);/* Synchronous operation */
typedef struct fingerprint_device {/*** Common methods of the fingerprint device. This *must* be the first member* of fingerprint_device as users of this structure will cast a hw_device_t* to fingerprint_device pointer in contexts where it's known* the hw_device_t references a fingerprint_device.*/struct hw_device_t common;/** Client provided callback function to receive notifications.* Do not set by hand, use the function above instead.*/fingerprint_notify_t notify;/** Set notification callback:* Registers a user function that would receive notifications from the HAL* The call will block if the HAL state machine is in busy state until HAL* leaves the busy state.** Function return: 0 if callback function is successfuly registered*                  or a negative number in case of error, generally from the errno.h set.*/int (*set_notify)(struct fingerprint_device *dev, fingerprint_notify_t notify);/** Fingerprint pre-enroll enroll request:* Generates a unique token to upper layers to indicate the start of an enrollment transaction.* This token will be wrapped by security for verification and passed to enroll() for* verification before enrollment will be allowed. This is to ensure adding a new fingerprint* template was preceded by some kind of credential confirmation (e.g. device password).** Function return: 0 if function failed*                  otherwise, a uint64_t of token*/uint64_t (*pre_enroll)(struct fingerprint_device *dev);/** Fingerprint enroll request:* Switches the HAL state machine to collect and store a new fingerprint* template. Switches back as soon as enroll is complete* (fingerprint_msg.type == FINGERPRINT_TEMPLATE_ENROLLING &&*  fingerprint_msg.data.enroll.samples_remaining == 0)* or after timeout_sec seconds.* The fingerprint template will be assigned to the group gid. User has a choice* to supply the gid or set it to 0 in which case a unique group id will be generated.** Function return: 0 if enrollment process can be successfully started*                  or a negative number in case of error, generally from the errno.h set.*                  A notify() function may be called indicating the error condition.*/int (*enroll)(struct fingerprint_device *dev, const hw_auth_token_t *hat,uint32_t gid, uint32_t timeout_sec);/** Finishes the enroll operation and invalidates the pre_enroll() generated challenge.* This will be called at the end of a multi-finger enrollment session to indicate* that no more fingers will be added.** Function return: 0 if the request is accepted*                  or a negative number in case of error, generally from the errno.h set.*/int (*post_enroll)(struct fingerprint_device *dev);/** get_authenticator_id:* Returns a token associated with the current fingerprint set. This value will* change whenever a new fingerprint is enrolled, thus creating a new fingerprint* set.** Function return: current authenticator id or 0 if function failed.*/uint64_t (*get_authenticator_id)(struct fingerprint_device *dev);/** Cancel pending enroll or authenticate, sending FINGERPRINT_ERROR_CANCELED* to all running clients. Switches the HAL state machine back to the idle state.* Unlike enroll_done() doesn't invalidate the pre_enroll() challenge.** Function return: 0 if cancel request is accepted*                  or a negative number in case of error, generally from the errno.h set.*/int (*cancel)(struct fingerprint_device *dev);/** Enumerate all the fingerprint templates found in the directory set by* set_active_group()* This is a synchronous call. The function takes:* - A pointer to an array of fingerprint_finger_id_t.* - The size of the array provided, in fingerprint_finger_id_t elements.* Max_size is a bi-directional parameter and returns the actual number* of elements copied to the caller supplied array.* In the absence of errors the function returns the total number of templates* in the user directory.* If the caller has no good guess on the size of the array he should call this* function witn *max_size == 0 and use the return value for the array allocation.* The caller of this function has a complete list of the templates when *max_size* is the same as the function return.** Function return: Total number of fingerprint templates in the current storage directory.*                  or a negative number in case of error, generally from the errno.h set.*/int (*enumerate)(struct fingerprint_device *dev, fingerprint_finger_id_t    *results,uint32_t *max_size);/** Fingerprint remove request:* Deletes a fingerprint template.* Works only within a path set by set_active_group().* notify() will be called with details on the template deleted.* fingerprint_msg.type == FINGERPRINT_TEMPLATE_REMOVED and* fingerprint_msg.data.removed.id indicating the template id removed.** Function return: 0 if fingerprint template(s) can be successfully deleted*                  or a negative number in case of error, generally from the errno.h set.*/int (*remove)(struct fingerprint_device *dev, uint32_t gid, uint32_t fid);/** Restricts the HAL operation to a set of fingerprints belonging to a* group provided.* The caller must provide a path to a storage location within the user's* data directory.** Function return: 0 on success*                  or a negative number in case of error, generally from the errno.h set.*/int (*set_active_group)(struct fingerprint_device *dev, uint32_t gid,const char *store_path);/** Authenticates an operation identifed by operation_id** Function return: 0 on success*                  or a negative number in case of error, generally from the errno.h set.*/int (*authenticate)(struct fingerprint_device *dev, uint64_t operation_id, uint32_t gid);//Add by zhangbin@meitu.com for MEITU_TAG_FINGERPRINT: update fpc_tac sw18.2/**  Set fingerprint model work mode, Just like DeepSleep :)*/int (*set_work_mode)(struct fingerprint_device *device, int mode);/**  Just Use in FactoryMode, unify factory test API*/int (*factory_test)(struct fingerprint_device *device, int argc, void* argv);/* Reserved for backward binary compatibility *///void *reserved[4];void *reserved[2];//Add end
} fingerprint_device_t;

我们需要在fingerprint.c/cpp 里面去实现这个fingerprint.h 里面的函数,即可。

  • enroll: 切换HAL状态机以启动指纹模板的收集和存储。 一旦注册完成或超时,HAL状态机将返回到空闲状态
  • pre_enroll:生成一个唯一的令牌来指示指纹注册的开始。 向注册功能提供token,以确保先前的身份验证,例如使用密码。 一旦设备凭证被确认,令牌就被包装并进行HMAC,以防止篡改。 在注册期间必须检查token,以验证token是否仍然有效。
  • pos_enroll: 完成注册操作并使pre_enroll()生成的challenge无效。 这将在多手指登录会话结束时调用,以指示不再添加手指
  • get_authenticator_id:返回与当前指纹集关联的token
  • cancel: 取消任何待处理的注册或验证操作。 HAL状态机返回到空闲状态。
  • enumerate:同步调用枚举所有已知的指纹模板
  • remove: 删除单个的指纹模板
  • set_active_group: 将HAL操作限制为属于指定组(由组标识符或GID标识)的一组指纹。
  • authenticate: 验证指纹相关操作(由操作ID标识)
  • set_notify - 注册将从HAL获取通知的用户功能。 如果HAL状态机处于忙状态,则该功能被阻塞,直到HAL离开忙碌状态

Android Fingerprint完全解析(三) :Fingerprint Hal层分析相关推荐

  1. android源码解析------Media多媒体framework层分析

    1.packages\providers\MediaProvider :含以下 java 文件 MediaProvider.java MediaScannerReceiver.java MediaSc ...

  2. Android系统的HAL层分析 -- Sensors

    Android系统HAL层分析 -- Sensors 0 前言 1 HAL层Sensors代码分析/注释 0 前言 1 HAL层Sensors代码分析/注释

  3. Android HAL层分析 (gralloc显示模块 举例)

     Android的HAL是为了保护一些硬件提供商的知识产权而提出的,是为了避开linux的GPL束缚.思路是把控制硬件的动作都放到了Android HAL中,而linux driver仅仅完成一些 ...

  4. Android序列化经典解析(三)-拨乱反正,堪比窦娥的Serializable

    关于网上很多博客提到Parcelable比Serializable快,原因大致有两种说法: Serializable基于反射来做的 Serializable基于磁盘进行序列化,而Parcel基于内存 ...

  5. GPS模块HAL层分析和调试

    主控: Samsung   Cortex  ARM A8  smdkc110  1G Gps:    Ublox-G6010 系统:  android 2.3 在android里关于普通GPS模块(俗 ...

  6. android l camera no panorama,Android Camera从App层到framework层到HAL层的初始化过程

    Android camera 从上到下能够分为四个部分: Application层. framework层. HAL(hardware abstract layer)层. Kernel层 通常面向开发 ...

  7. Android HAL层浅析

    文章目录 1.HAL层在Android系统中的位置 2.HAL层概述 3.旧的HAL架构module 4.新的HAL架构module stub 5.HAL Stub框架分析 1.HAL层在Androi ...

  8. Android Audio 服务层与HAL层之间的接口分析 Service<->interface<->HAL

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.AudioFlinger 二.服务层接口分析 2.1由DevicesFactoryHalInterface可以找到Dev ...

  9. Android HAL层/native C程序打印栈信息方法

    在调试Android系统底层函数时,经常需要跟踪函数调用流程,特别在HAL层需要确定参数来源时.使用栈信息逆向跟踪可快速分析函数调用流程,结合使用addr2line工具.绘图工具可绘制函数关系图.本文 ...

  10. Android Volley完全解析2:使用Volley加载网络图片

    原文链接:http://blog.csdn.net/guolin_blog/article/details/17482165,CSDN 郭霖 在上一篇文章中,我们了解了Volley到底是什么,以及它的 ...

最新文章

  1. Spring JdbcTemplate的queryForList(String sql , Class<T> elementType)返回非映射实体类的解决方法
  2. 《青春飞扬》诗集出版历程与思考分享 之三:游记、感悟与思考
  3. linux系统root默认密码是多少钱,linux root默认密码忘记后的解决方法
  4. Linux系统删掉多个文件
  5. 《Kali+Linux渗透测试的艺术》学习总结之----Kali Linux简介
  6. Java中int和Integer的区别
  7. matlab低通滤波器库函数代码_Matlab中模拟低通滤波器的函数
  8. extern 头文件 定义声明
  9. 自写的简单屏蔽特定字符的TextBox和数字TextBox
  10. 限时下载 | 132G编程资料:Python、JAVA、C,C++、机器人编程、PLC,入门到精通~
  11. Mobilenet-ssd 目标检测
  12. 演示固态硬盘装win11系统教程
  13. 云购系统、一元云购系统接入短信验证及订单通知功能
  14. 计算机c盘崩了,崩溃,C盘爆红了!试试这5款电脑清理工具,每一个都很实用
  15. 作为一个平面设计师,该如何转变平面设计思维
  16. 计算机毕业设计 SSM的房屋租赁管理系统(源码+论文)
  17. 项目经理和团队如何产生距离美?
  18. UE4构建光照后,BSP创建的静态网格变全黑
  19. UE4-(反射)平面反射
  20. Unix Linux、MAC、Window 如何安装配置环境?都在这里啦~

热门文章

  1. 如何免费将jpg转换为word可编辑
  2. 腾达ac5第三方固件_腾达AC9的刷固件指南
  3. java中求数组中最大值
  4. centOS服务器 netstat命令 查看TCP连接数信息(转)
  5. windows删除桌面右键“英特尔@显卡设置”
  6. win10 应用商店打不开解决
  7. 微信小程序 input、picker组件
  8. 阿里云企业邮箱的imap和pop3设置
  9. 视频会议系统gk服务器,TENKING- 远程视频会议系统
  10. SU战队专访:破而后立,晓喻新生