1.4 配件配置后的主要状态- Synchronization mode:在已配置(Provisioned)状态下,配件在系统重启后(例如,因更换电池而重启)会尝试同步其信标时钟。在这种情况下,它会发起 Fast Pair not Discoverable Advertising,以表明安卓设备需要与定位标签进行同步。智能手机检测Fast Pair not Discoverable Advertising后,会连接到该配件,并交换必要的数据,以便将其信标时钟与已连接设备的当前时钟值进行同步。在成功同步之后,定位标签会停止Fast Pair not Discoverable Advertising。从这时起,该配件开始FMDN Beacon Advertising。另外,安卓设备采用了一种限流机制,以防止信标时钟同步在每 24 小时内发生超过一次。配置(Provisioning)操作也被视为一次时钟同步事件,并且在下一次同步尝试之前需要等待 24 小时的时间间隔。(同步是安卓设备发起的)
- Identification mode: 在已配置状态下,可以在有限时间内进入识别模式。此模式允许已连接的设备从定位标签读取识别信息。这类识别信息的一个例子是通过蓝牙读取蓝牙通用访问配置文件(GAP)中的设备名称。识别模式还允许读取在《检测不必要的位置追踪器(DULT)》规范中定义的标识符有效载荷。识别模式的超时由 DULT 子系统处理,引入这一机制是为了提高用户隐私保护程度。
- Recovery mode:在已配置状态下,可以在有限时间内进入恢复模式。此模式允许安卓设备从定位标签中找回丢失的配置密钥EIK
- Motion detector mode:在已配置状态下, 配件可以激活《检测不必要的位置追踪器(DULT)》规范中定义的运动检测模式。当配件与所有者分离足够长的时间后(请参考配置选项:CONFIG_DULT_MOTION_DETECTOR_SEPARATED_UT_TIMEOUT_PERIOD_MIN 和 CONFIG_DULT_MOTION_DETECTOR_SEPARATED_UT_TIMEOUT_PERIOD_MAX),该模式将被激活。在这种状态下,如果检测到运动,配件就会启动响铃操作。发出的声音有助于提醒非所有者,他们携带了一个不属于自己的配件,并且原所有者可能会利用这个配件来追踪他们的位置。在DK上,可以通过按下按钮来模拟产生运动。在 Thingy:53 设备上,内置的加速度计被用于检测运动。在播放10次声音后,或者在检测到运动且过去20秒之后,运动检测器将在配置选项CONFIG_DULT_MOTION_DETECTOR_SEPARATED_UT_BACKOFF_PERIOD 中所设置的时间段内处于停用状态。如果配件再次出现在其所有者附近,运动检测器也会被停用。
- factory reset:配件执行工厂复位操作后,发生工厂复位(factory reset),配置数据被删除,需要重新配置。配件启动(reset)的过程中按下Button4(nRF 52840 DK),执行factory reset。
1.5 配件必须包含的蓝牙服务配件必须包含fast pair GATT service(UUID 0xFE2C)和Accessory non-owner GATT service(UUID 0x15190001-12F4-C226-88ED-2AC5579F2A85),如下图: 通过fast pair GATT service里面的Bluetooth LE特征可以完成对配件的配置以及实现所有者设备(如Android手机)对配件的操控;通过accessory non-owner GATT service里面的Bluetooth LE特征可以实现非所有者设备(如Android手机)对配件的操控。Accessory non-owner GATT service用于实现DULT(Detecting Unwanted Location Trackers )协议,用来解决非法跟踪的问题Unwanted tracking prevention。 关于配件的配置主要包含两个阶段(一次连接就可以完成):第一阶段是通过Google fast pair获取account key,第二阶段是做provisioning获取临时身份密钥EIK(Ephemeral identity key)。关于第一阶段的详细介绍可以参考前一篇博客:Google快速配对服务(Google Fast Pair Service)详解和应用;第二阶段的配置(provisioning)过程,通过Beacon actions这个Bluetooth LE特征作为逻辑通道,由所有者设备发送Beacon Provisioning Request命令开始触发配置(provisioning)过程。Beacon actions的定义如下: 基于Beacon actions通道的每一个命令的通信流程如下: Seeker(所有者设备)进行Bluetooth LE读操作的目的是从Provider(配件)处获得一个Nonce随机数和协议主版本号,用来生成one-time authentication key,用于身份认证; Seeker 通过Bluetooth LE写请求命令给Provider发送命令,Provider通过Notification的方式发送命令响应。Beacon actions特性的代码定义: /* Beacon Actions GATT Characteristic definition for the Fast Pair service. */#define FP_FMDN_BEACON_ACTIONS_CHARACTERISTIC \ BT_GATT_CHARACTERISTIC(BT_FAST_PAIR_UUID_BEACON_ACTIONS, \ BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_NOTIFY, \ BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, \ fp_fmdn_beacon_actions_read, \ fp_fmdn_beacon_actions_write, \ NULL), \ BT_GATT_CCC(fp_fmdn_beacon_actions_ccc_cfg_changed, \ BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)
Bluetooth LE读操作响应callback函数如下,函数里提供了Nonce随机数和协议主版本号 ssize_t fp_fmdn_beacon_actions_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset){ int err; ssize_t res; struct conn_context *conn_context; uint8_t rsp[BEACON_ACTIONS_READ_RSP_LEN]; BUILD_ASSERT((sizeof(conn_context->random_nonce) + BEACON_ACTIONS_READ_RSP_VERSION_LEN) == BEACON_ACTIONS_READ_RSP_LEN); /* It is assumed that this callback executes in the cooperative thread context. */ __ASSERT_NO_MSG(!k_is_preempt_thread()); __ASSERT_NO_MSG(!k_is_in_isr()); LOG_DBG("Beacon Actions GATT Read Request"); /* Do not perform any action if Fast Pair is not ready. */ if (!bt_fast_pair_is_ready()) { res = BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); LOG_INF("Beacon Actions read: res=%d conn=%p, " "Return error because Fast Pair is not enabled", res, (void *)conn); return res; } conn_context = &conn_contexts[bt_conn_index(conn)]; err = sys_csrand_get(conn_context->random_nonce, sizeof(conn_context->random_nonce)); if (err) { LOG_ERR("Beacon Actions: failed to generate random nonce: err=%d", err); return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY); } rsp[0] = CONFIG_BT_FAST_PAIR_FMDN_VERSION_MAJOR; memcpy(&rsp[BEACON_ACTIONS_READ_RSP_VERSION_LEN], conn_context->random_nonce, sizeof(conn_context->random_nonce)); res = bt_gatt_attr_read(conn, attr, buf, len, offset, rsp, sizeof(rsp)); if (res == sizeof(rsp)) { conn_context->is_challenge_valid = true; LOG_HEXDUMP_DBG(conn_context->random_nonce, sizeof(conn_context->random_nonce), "Beacon Actions: challenge-response enabled for the next write:"); } LOG_DBG("Beacon Actions read: res=%d conn=%p", res, (void *)conn); return res;}
1.6 基于Beacon actions特性的命令1.6.1 信标配置请求命令(Beacon provisioning request)配置过程包括fast pair和provisioning两个阶段。Provisioning过程主要围绕Beacon provisioning request和response过程进行。信标配置请求命令格式如下: 信标配置请求命令含4个子命令:读取信标参数,读取配置状态,设置EIK和清除EIK 信标配置请求命令的一次性认证密钥(One-time authentication key)采用 HMAC-SHA256 算法计算结果并取结果的前 8 个字节的数据。HMAC(Hash - based Message Authentication Code,基于哈希的消息认证码)是一种通过使用哈希函数(这里是 SHA256)来生成消息认证码的机制。它结合了一个密钥(account key)和待认证的数据(协议主版本号 || 从该特性读取的最后一个随机数 || 数据 ID || 数据长度 || 附加数据,注:“||” 表示拼接操作),从而生成一个固定长度的哈希值。协议主版本号和随机数是对Beacon actions特征读操作过程中获取的。
|