| RFC-0035:自动流跟踪 | |
|---|---|
| 状态 | 已拒绝 |
| 区域 |
|
| 说明 | 通过向 FIDL 绑定添加跟踪事件,我们可以在 Fuchsia 上实现跨进程的端到端流,而无需手动滚动自定义 ID。 |
| 作者 | |
| 提交日期(年-月-日) | 2019-02-28 |
| 审核日期(年-月-日) | 2019-02-28 |
拒绝理由
没有响应的消息(无论是事件还是即发即弃调用)的事务 ID 都设置为 0,因此无法使用建议的方案进行区分。
某些用途利用 zx_channel_call(),该函数在内核中分配 事务 ID 并等待回复。 (此模式允许并发调用方依赖内核同步,从而避免为事务 ID 分配使用用户空间锁。)同样,建议的方案也无法区分这些。
我们预计内核跟踪支持会提供此审核所需的遥测数据,并且我们倾向于改进此机制,而不是在 FIDL 绑定中推送此机制。
最后,在 SDK 依赖项优先级中,由于 FIDL 在 Fuchsia 上广泛使用,因此使用 FIDL 和使用 FIDL 绑定非常接近顶部。 因此,在绑定中包含遥测数据和指标会引发对该优先级的担忧,而我们对此并不满意。 可以考虑一些构建和选择性加入技巧,并且需要将其纳入未来的提案。
摘要
通过向 FIDL 绑定添加跟踪事件,我们可以在 Fuchsia 上实现跨进程的端到端流,而无需手动滚动自定义 ID。
设计初衷
在 Fuchsia 上,有大量黑客攻击可以跨进程边界启用流事件。 我们可以自动执行其中的大部分操作,而不会使我们的 API 表面复杂化,并且需要较少的手动工作。
设计
Fuchsia FIDL 函数的标准属性,可向其各自生成的绑定添加流开始/结束事件。
该属性设置跟踪的类别,并使用协议函数作为名称。 Fuchsia 上的跟踪目前仅支持一个类别,因此虽然该属性可能包含 N 个类别,但我们预计只会使用一个类别,并且会使用列表中的第一个类别。
protocol Example {
[Trace = "CATEGORY"]
ExampleFn(bool test) -> (bool status);
};
唯一的跨进程 ID 是序号 ID、交易 ID(包含在每条消息中)和传输机制的 ID(对于 zircon 通道:发送进程通道句柄的 koid,以及接收进程句柄的相关 koid)与非加密哈希一起进行哈希处理。
通过 zx 通道的 FIDL 的稳定跟踪 ID 示例
我们建议组合几个标识符:
- FIDL 通道的服务器端的 koid,可以使用
zx_object_get_info()获取,
主题为
ZX_INFO_HANDLE_BASIC,使用 服务器端的 koid 和客户端的相关 koid; - 事务消息的方法序号 (注意:这 目前是一个 uint32 哈希值,很快将演变为 uint64 哈希值,请参阅 RFC-0029);
- 最后,事务 ID 的 事务消息。
组装这三个标识符的方式应力求减少可能的跟踪 ID 冲突,优先级如下:
- 在两条不同的消息之间,具有相同的序号,并且在 相同的客户端和服务器之间;
- 在两条不同的消息之间,具有不同的序号,并且在 相同的客户端和服务器之间;
- 在两条不同的消息之间,具有不同的序号,并且在 不同的客户端和服务器之间。
目前,koid 分配大多是按顺序进行的。因此,koid 的最低位将比最高位具有更多的熵。 同样,事务 ID 是按顺序分配的,因此在最低位中提供更多熵。 方法序号是经过加密哈希处理的,尽管最高位保留供系统使用,但可以安全地假设所有位都具有相同的熵。
因此,在当前条件下,合理的算法是 OR:
koid & OxFFFF << 48ordinal & 0xFFFFFFFF << 16transaction ID & 0xFF << 0
跟踪时长也会在 FIDL 绑定的接收端启动。 对于 C++/Rust 等语言,这使用 RAII 进行限定,并允许将事件与另一个流事件缝合在一起。
工效学设计
这使得我们的跟踪系统更易于使用,这对我们的基础架构来说也是一个巨大的胜利。
文档和示例
应更新文档,以显示如何添加跟踪(如上所述)。
向后兼容性
此更改与 API 兼容,并且与 ABI 兼容。
性能
当跟踪类别被停用时,这将产生少量费用,每次 dje@google.com 测试(在 NUC 上)的费用不到 5 纳秒。 如果需要更高的性能,我们还可以从 IR 中剥离跟踪注解。
安全
无安全注意事项。
缺点、替代方案和未知事项
替代方案
内核跟踪机制
利用通道读取和通道写入中现有的 ktrace 流事件。
如果没有此功能,则可以尝试通过使用底层通道读取和写入中现有的 ktrace 流事件来实现此目的。 不过,这是不可取的,因为通道对于所有 FIDL 接口都是通用的,这意味着只能指定一个类别。 这意味着,为了实际使用,用户必须启用通道读取和通道写入类别,这意味着所有通道读取和写入事件(而不仅仅是用于感兴趣的 FIDL 接口的事件)都将存在。这会导致跟踪查看器输出更难读取,不必要的 ktrace 缓冲区使用,并且还依赖于 FIDL 实现细节。