防止数据处理流水线中的系统挂起
在许多情况下,一个事件需要多个组件参与其处理。假设您是一位驱动程序,收到一个可能会唤醒系统的事件,或者如果是在系统处于唤醒状态时收到该事件,则应阻止系统挂起。中断处理驱动程序可能不知道事件的重要性,并将其传递给另一个驱动程序或组件,这种情况非常常见。
您可以通过几种可选方法来管理这种交接。为了便于讨论,我们假设驱动程序 X 接收到中断,并通过 FIDL 消息将事件交给驱动程序 Y。如果 X 是驱动程序,而 Y 是非驱动程序组件,这些选项同样适用。
接力棒传递
解决此问题的一种方法是随事件数据一起传递接力棒。“接力”是指接力赛中参与者将物体从一个传递给另一个,以完成任务(即比赛)。
接力棒可以是 LeaseToken(我们之前讨论过)或 fuchsia.power.broker/LeaseControl 渠道。我们将使用 LeaseToken,因为我们已经讨论过它们,而且它们比 LeaseControl 更易于使用。
当 X 收到中断时,它会:
- 调用
ActivityGovernor.AcquireWakeLease - 确认中断
- 对事件执行任何处理,可能将其转换为新类型
- 将事件和从
AcquireWakeLease获取的LeaseToken传递给 Y
此方法需要更改 X 和 Y 之间使用的协议。使用下文所述的协议互锁不需要这样做,但有其他缺点。
对于事件速率较高的系统,调用 ActivityGovernor.AcquireWakeLease 的 IPC 开销可能过高,无法在每个事件上执行。在这些情况下,驱动程序 X 可以复制 LeaseToken(因为它实际上只是 Zircon 事件对的句柄),传递副本,并在某个超时时段内保留原始句柄,而不是简单地将 LeaseToken 从 X 移至 Y。LeaseToken如果选择使用超时,请谨慎选择超时时间,因为系统在所有 LeaseToken 副本都被丢弃之前无法暂停。
强烈建议不要使用过长的超时时间,使用超时时间的原因是您的事件速率相对较高,这意味着您应该能够选择较短的超时时间。如果您编写的是 C++ 代码,可以使用 TimeoutWakeLease 类来管理租约,并根据新事件的到达情况延长超时时间。通过调用 AcquireWakeLease 来使用辅助功能,而不是自行与 ActivityGovernor 功能对话。
协议互锁
如果驱动程序 X 和驱动程序 Y 的事件传递协议包含确认或添加了确认,则可以选择“协议互锁”。协议互锁是通过以下方式实现的:Y 在向 X 确认 Y 已收到事件之前调用 ActivityGovernor.AcquireWakeLease。
此方法的步骤如下:
- X 次通话
ActivityGovernor.AcquireWakeLease - 确认中断
- X 对事件执行任何必要的处理,可能会将其转换为新类型
- 将事件传递给 Y
- Y 通话
ActivityGovernor.AcquireWakeLease - Y 向 X 确认已收到事件
- X 丢弃了其
LeaseToken - Y 对事件执行任何处理
- Y 丢弃了其
LeaseToken
如果协议已经具有确认机制,则协议互锁不需要更改 X 和 Y 之间使用的协议。此策略确实会增加对系统 activity 管理器的 IPC 调用次数。调用次数的增加是否有意义取决于事件的速率,以及 X 和 Y 是否在超时期限内保留其 LeaseToken。如果您选择使用超时,请谨慎选择超时时间,因为在 LeaseToken 丢弃之前,系统将无法暂停。强烈建议不要使用过长的超时时间,使用超时时间的原因是您的事件速率相对较高,这意味着您应该能够选择较短的超时时间。如果您编写的是 C++,则可以使用 TimeoutWakeLease 类来管理租约并根据新事件的到达情况延长超时时间。通过调用 AcquireWakeLease 来使用辅助功能,而不是自行与 ActivityGovernor 功能对话。
超时
使用超时来确保系统正确性不是与电源框架集成时的首选方案。其他选项仅将超时用作优化。由于很难找到合适的超时值,因此超时可能会导致不可预测的行为。此外,通常必须针对每种使用情形、产品配置和硬件配置组合调整超时时间,这使得管理超时时间成为一项艰巨的任务。超时本身就具有竞争性,因此对于任何给定的超时值,它可能允许您在大多数情况下赢得竞争,直到突然无法赢得竞争为止。只有在软件部署到大量测试人员或用户群后,才会发现故障,并且在观察到故障时会造成混乱。
有时,超时是唯一可行的选择。如果设置了超时时间,驱动程序 X 将调用 ActivityGovernor.AcquireWakeLease,确认中断,然后持有租约直到达到超时时间,驱动程序 Y 永远不会看到该租约。如果在超时之前收到另一个中断,驱动程序 X 可以只延长其超时时间,而无需获取额外的租约。如果您在编写 C++ 代码,可以使用一个辅助类来管理租约并根据新中断的到达情况延长超时时间。通过调用 AcquireWakeLease 来使用辅助功能,而不是自行与 ActivityGovernor 功能对话。