Android Fingerprint完全解析(三) :Fingerprint Hal层分析

#Fingerprint Hal层分析#

##一前言##

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

##一.Android 含有硬件抽象层的框架图 ##
Android Fingerprint完全解析(三) :Fingerprint Hal层分析_第1张图片

##二.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 ".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 different
                   file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch",
"ro.btstack"
};

  硬件抽象层模块文件命名规范是.variant.so ;其中,MODULE_ID 表示的是模块的ID ,后边会介绍,variant 表示下面的几个系统属性ro.hardware、ro.product.board、ro.board.platform、ro.arch和ro.btstack其中的一个。系统在加载硬件抽象层模块时候,依次按照其顺序来去它们的属性值。如果其中一个属性值存在,那么就把它的值作为variant,然后再检查对应的硬件抽象层文件是否存在,如果,存在,那么就加载此.so文件;否则,就继续查找下一个系统属性。如果都不存在,那么就以.default.som来命名(fingerprint.default.so 就是这么来的)。

####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);
	else
    	strlcpy(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

   hw_get_module() 会调用hw_get_module_by_class函数,首先通过property_get 函数获取系统属性"ro.hardware"的值,如果找到,则通过hw_module_exists 函数去查找.so 文件存不存在。如果存在,直接加载;不存在,就再继续查找variant_keys 数组中,其他的系统属性值存不存在。如果存在,直接加载,不存在,则最后去加载.default.so文件。如果此文件也不存在,那么硬件抽象层模块加载失败了。

	static int load(const char *id,
    	const char *path,
    	const struct hw_module_t **pHmi)
{
	int status = -EINVAL;
	void *handle = NULL;
	struct hw_module_t *hmi = NULL;

	/*
 	* load the symbols resolving undefined symbols before
 	* dlopen returns. Since RTLD_GLOBAL is not or'd in with
 	* RTLD_NOW the external symbols will not be global
 	*/
	
	handle = dlopen(path, RTLD_NOW);
	if (handle == NULL) {
   		char const *err_str = dlerror();
    	ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
    	status = -EINVAL;
    	goto done;
	}

	/* Get the address of the struct hal_module_info. */
	const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
	hmi = (struct hw_module_t *)dlsym(handle, sym);
	if (hmi == NULL) {
    	ALOGE("load: couldn't find symbol %s", sym);
    	status = -EINVAL;
    	goto done;
	}

/* Check that the id matches */
if (strcmp(id, hmi->id) != 0) {
    ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
    status = -EINVAL;
    goto done;
}

hmi->dso = handle;

/* success */
status = 0;

done:
if (status != 0) {
    hmi = NULL;
    if (handle != NULL) {
        dlclose(handle);
        handle = NULL;
    }
} else {
    ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
            id, path, *pHmi, handle);
}

	*pHmi = hmi;

	return status;
}

  前面已经说过的,硬件抽象层模块,最后其实被打包成一个动态链接库.so 文件。上面的Load函数中,通过dlopen 函数加载此.so文件到内存中,然后调用dlsym函数来获取HAL_MODULE_INFO_SYM_AS_STR这个符号。这个符号里面包含硬件抽象层模块的所有信息。根据前面硬件抽象层模块的编写规范, HAL_MODULE_INFO_SYM_AS_STR 的值被定义为"HMI",且每一个硬件抽象层模块都必须包含一个名称为"HMI"的符号,且这个符号的第一个成员变量的类型必须定义成hw_module_t。因此,可以将HMI
强转成一个hw_module_t 的结构体指针。后边会调用strcmp 函数来验证加载得到的硬件抽象层模块ID跟所要求加载的ID 是否一致。如果一致就说明成功了,最好会把handle 保存在结构体指针hmi的成员变量dso中,返还给调用者。

  以上就是硬件抽象模块的加载过程

##四.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 [email protected] 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,指纹)