Skip to main content

driver_lab_rust/
server.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! FIDL server for the `fuchsia.driver.lab` wire contract, bridging the
6//! host-facing protocol to the host-testable core logic.
7
8use crate::fuchsia_backends::LiveBackend;
9use fidl_fuchsia_driver_lab as flab;
10use fuchsia_async::ScopeHandle;
11use futures::{FutureExt as _, TryStreamExt};
12use lab_proxy_core::access_policy::{AccessClass, AccessRule, Denial, WritePrecondition};
13use lab_proxy_core::audit_ring::{AuditRecord, AuditRing, Decision, OpStatus};
14use lab_proxy_core::executor::{
15    ClockOpError, Executor, GpioReadError, GpioWriteError, I2cTransferError, PollError, ReadError,
16    ResetOpError, SequenceItem as CoreSequenceItem, SerialOpError, SnapshotError, SnapshotItem,
17    SpiTransmitError, WriteError,
18};
19use lab_proxy_core::hardware_backend::Clock;
20use lab_proxy_core::interrupt::InterruptManager;
21use lab_proxy_core::session::{OpenError, ProxyIdentity, RunContext, SessionManager, SessionMode};
22use std::sync::{Arc, Mutex};
23
24fn fidl_to_core_sequence_item(item: &flab::SequenceItem) -> Option<CoreSequenceItem> {
25    match item {
26        flab::SequenceItem::Read32(read) => {
27            Some(CoreSequenceItem::Read32 { resource: read.resource, offset: read.offset })
28        }
29        flab::SequenceItem::Write32(write) => Some(CoreSequenceItem::Write32 {
30            resource: write.resource,
31            offset: write.offset,
32            value: write.value,
33            write_mask: write.write_mask,
34            precondition: write
35                .precondition
36                .as_ref()
37                .map(|p| WritePrecondition { expected: p.expected, mask: p.mask }),
38            readback: write.readback,
39        }),
40        flab::SequenceItem::Poll32(poll) => Some(CoreSequenceItem::Poll32 {
41            resource: poll.resource,
42            offset: poll.offset,
43            expected: poll.expected,
44            mask: poll.mask,
45            interval_ns: poll.interval_ns,
46            timeout_ns: poll.timeout_ns,
47        }),
48        flab::SequenceItem::DelayNs(delay) => Some(CoreSequenceItem::DelayNs(*delay)),
49        flab::SequenceItem::Barrier(_) => Some(CoreSequenceItem::Barrier),
50        flab::SequenceItem::GpioRead(read) => {
51            Some(CoreSequenceItem::GpioRead { resource: read.resource })
52        }
53        flab::SequenceItem::GpioWrite(write) => {
54            Some(CoreSequenceItem::GpioWrite { resource: write.resource, value: write.value })
55        }
56        flab::SequenceItem::I2cTransfer(transfer) => Some(CoreSequenceItem::I2cTransfer {
57            resource: transfer.resource,
58            write_data: transfer.write_data.clone(),
59            read_length: transfer.read_length,
60        }),
61        flab::SequenceItem::SpiTransmit(transmit) => Some(CoreSequenceItem::SpiTransmit {
62            resource: transmit.resource,
63            tx_data: transmit.tx_data.clone(),
64        }),
65        _ => None,
66    }
67}
68
69/// Wire-contract version served by this driver.
70pub const PROTOCOL_MAJOR: u32 = 1;
71/// Wire-contract minor version.
72pub const PROTOCOL_MINOR: u32 = 0;
73
74/// Clock backed by zx monotonic time.
75#[derive(Debug, Default)]
76pub struct ZxClock;
77
78impl Clock for ZxClock {
79    fn now_ns(&mut self) -> i64 {
80        zx::MonotonicInstant::get().into_nanos()
81    }
82}
83
84impl lab_proxy_core::hardware_backend::Timer for ZxClock {
85    async fn sleep(&mut self, duration_ns: i64) {
86        if duration_ns > 0 {
87            fuchsia_async::Timer::new(zx::MonotonicInstant::after(zx::Duration::from_nanos(
88                duration_ns,
89            )))
90            .await;
91        }
92    }
93}
94
95/// Shared proxy state behind one lock and cancellation token.
96#[derive(Debug)]
97pub struct ProxyState {
98    /// Session lifecycle and per-session policy.
99    pub sessions: SessionManager,
100    /// The shared read-path executor over the acquired MMIO mappings.
101    pub executor: Executor<LiveBackend, ZxClock>,
102    /// The instance audit ring.
103    pub audit: AuditRing,
104    /// Per-resource description digests, reported by `Describe` for
105    /// persistent grant matching.
106    pub resource_digests: std::collections::BTreeMap<u32, String>,
107    /// Interrupt manager coordinating interrupt observations.
108    pub interrupts: InterruptManager,
109    /// Structured configuration bounds.
110    pub config: lab_proxy_core::config::ProxyConfig,
111}
112
113/// Handle to the shared proxy state and cancellation token.
114pub struct SharedStateData {
115    pub inner: Mutex<ProxyState>,
116    pub abort_token: std::sync::atomic::AtomicBool,
117}
118
119pub type SharedState = Arc<SharedStateData>;
120
121fn now_ns() -> i64 {
122    zx::MonotonicInstant::get().into_nanos()
123}
124
125fn denial_to_fidl(denial: Denial) -> flab::OperationError {
126    match denial {
127        Denial::UnknownResource => flab::OperationError::UnknownResource,
128        Denial::UnsupportedWidth => flab::OperationError::UnsupportedWidth,
129        Denial::UnsupportedAccessClass => flab::OperationError::UnsupportedAccessClass,
130        Denial::Misaligned => flab::OperationError::Misaligned,
131        Denial::OffsetOverflow => flab::OperationError::OffsetOverflow,
132        Denial::OutOfLogicalBounds => flab::OperationError::OutOfLogicalBounds,
133        Denial::OutOfMappedBounds => flab::OperationError::OutOfMappedBounds,
134        Denial::NotPermittedByCeiling => flab::OperationError::NotPermittedByCeiling,
135        Denial::HardDenied => flab::OperationError::HardDenied,
136        Denial::UnknownReadsNotPermitted => flab::OperationError::UnknownReadsNotPermitted,
137        Denial::PollNotPermitted => flab::OperationError::PollNotPermitted,
138        Denial::NotInAllowlist => flab::OperationError::NotInAllowlist,
139        Denial::LimitExceeded => flab::OperationError::LimitExceeded,
140        Denial::StaleIdentity => flab::OperationError::StaleIdentity,
141        Denial::MutationLeaseContention => flab::OperationError::MutationLeaseContention,
142        Denial::NotAccepting => flab::OperationError::NotAccepting,
143        Denial::UnsupportedExpectation => flab::OperationError::UnsupportedExpectation,
144        Denial::PreconditionFailed => flab::OperationError::PreconditionFailed,
145        Denial::MissingPrecondition => flab::OperationError::MissingPrecondition,
146        Denial::Timeout => flab::OperationError::Timeout,
147        Denial::ReadOnlySession => flab::OperationError::ReadOnlySession,
148        Denial::WriteNotPermitted => flab::OperationError::WriteNotPermitted,
149        Denial::UnsupportedMethod => flab::OperationError::UnsupportedMethod,
150        Denial::TransferTooLarge => flab::OperationError::TransferTooLarge,
151    }
152}
153
154fn open_error_to_fidl(error: &OpenError) -> flab::OpenSessionError {
155    match error {
156        OpenError::NotAccepting => flab::OpenSessionError::NotAccepting,
157        OpenError::StaleBootId => flab::OpenSessionError::StaleBootId,
158        OpenError::StaleProxyGeneration => flab::OpenSessionError::StaleProxyGeneration,
159        OpenError::StaleResourceDigest => flab::OpenSessionError::StaleResourceDigest,
160        OpenError::StalePolicyDigest => flab::OpenSessionError::StalePolicyDigest,
161        OpenError::RejectedAllowlist { .. } => flab::OpenSessionError::RejectedAllowlist,
162        OpenError::MutationLeaseHeld | OpenError::MutationNotPermitted => {
163            flab::OpenSessionError::MutationLeaseHeld
164        }
165        OpenError::UnsupportedExpectation => flab::OpenSessionError::UnsupportedExpectation,
166    }
167}
168
169fn open_error_denial(error: &OpenError) -> Denial {
170    match error {
171        OpenError::NotAccepting => Denial::NotAccepting,
172        OpenError::StaleBootId
173        | OpenError::StaleProxyGeneration
174        | OpenError::StaleResourceDigest
175        | OpenError::StalePolicyDigest => Denial::StaleIdentity,
176        OpenError::RejectedAllowlist { denial, .. } => *denial,
177        OpenError::MutationLeaseHeld => Denial::MutationLeaseContention,
178        OpenError::MutationNotPermitted => Denial::NotPermittedByCeiling,
179        OpenError::UnsupportedExpectation => Denial::UnsupportedExpectation,
180    }
181}
182
183fn describe(state: &SharedState) -> flab::ProxyDescription {
184    let state = state.inner.lock().unwrap();
185    let identity = state.sessions.identity();
186    let resources: Vec<flab::ResourceDescription> = state
187        .sessions
188        .resources()
189        .iter()
190        .map(|(id, resource)| flab::ResourceDescription {
191            id: Some(*id),
192            name: Some(resource.name.clone()),
193            kind: Some(match resource.kind {
194                lab_proxy_core::access_policy::ResourceKind::Mmio => flab::ResourceKind::Mmio,
195                lab_proxy_core::access_policy::ResourceKind::Gpio => flab::ResourceKind::Gpio,
196                lab_proxy_core::access_policy::ResourceKind::I2c => flab::ResourceKind::I2C,
197                lab_proxy_core::access_policy::ResourceKind::Spi => flab::ResourceKind::Spi,
198                lab_proxy_core::access_policy::ResourceKind::Interrupt => {
199                    flab::ResourceKind::Interrupt
200                }
201                lab_proxy_core::access_policy::ResourceKind::Clock => flab::ResourceKind::Clock,
202                lab_proxy_core::access_policy::ResourceKind::Reset => flab::ResourceKind::Reset,
203                lab_proxy_core::access_policy::ResourceKind::Serial => flab::ResourceKind::Serial,
204            }),
205            logical_size: Some(resource.logical_size),
206            digest: state.resource_digests.get(id).cloned(),
207            ..Default::default()
208        })
209        .collect();
210    flab::ProxyDescription {
211        protocol_major: Some(PROTOCOL_MAJOR),
212        protocol_minor: Some(PROTOCOL_MINOR),
213        proxy_generation: Some(identity.proxy_generation),
214        boot_id: Some(identity.boot_id.clone()),
215        resource_digest: Some(identity.resource_digest.clone()),
216        policy_digest: Some(identity.policy_digest.clone()),
217        resources: Some(resources),
218        max_snapshot_items: Some(state.executor.limits().max_snapshot_items as u32),
219        audit_capacity: Some(state.audit.capacity() as u64),
220        // Phase 1 never activates takeover; node_moniker and
221        // topology_generation stay absent until the proxy binds to a
222        // real node.
223        takeover: Some(flab::TakeoverState::NotActive),
224        ..Default::default()
225    }
226}
227
228fn open_session(
229    state: &SharedState,
230    context: flab::RunContext,
231    mode: flab::SessionMode,
232    expectations: flab::Expectations,
233    allowlist: Vec<flab::AccessRule>,
234) -> Result<u64, OpenError> {
235    let context = RunContext {
236        run_id: context.run_id.unwrap_or_default(),
237        case_id: context.case_id.unwrap_or_default(),
238        plan_digest: context.plan_digest.unwrap_or_default(),
239        host_tool_version: context.host_tool_version.unwrap_or_default(),
240    };
241    if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
242        let mut state = state.inner.lock().unwrap();
243        state.audit.append(AuditRecord {
244            session: None,
245            resource: None,
246            operation: "open_session",
247            offset: None,
248            decision: Decision::Denied(Denial::NotAccepting),
249            status: OpStatus::Rejected,
250            value: None,
251            timestamp_ns: now_ns(),
252            run_id: Some(context.run_id),
253            item_index: None,
254        });
255        return Err(OpenError::NotAccepting);
256    }
257    let mode = match mode {
258        flab::SessionMode::ReadOnly => SessionMode::ReadOnly,
259        flab::SessionMode::Mutating => SessionMode::Mutating,
260    };
261    // Reserved phase 2 expectations fail closed rather than being
262    // silently ignored.
263    if expectations.topology_generation.is_some() || expectations.bound_driver_url.is_some() {
264        let mut state = state.inner.lock().unwrap();
265        state.audit.append(AuditRecord {
266            session: None,
267            resource: None,
268            operation: "open_session",
269            offset: None,
270            decision: Decision::Denied(Denial::UnsupportedExpectation),
271            status: OpStatus::Rejected,
272            value: None,
273            timestamp_ns: now_ns(),
274            run_id: Some(context.run_id),
275            item_index: None,
276        });
277        return Err(OpenError::UnsupportedExpectation);
278    }
279    // A required expectation the host omitted can never match the real
280    // identity, so absence falls through to the per-field stale check.
281    let expectations = ProxyIdentity {
282        boot_id: expectations.boot_id.unwrap_or_default(),
283        proxy_generation: expectations.proxy_generation.unwrap_or_default(),
284        resource_digest: expectations.resource_digest.unwrap_or_default(),
285        policy_digest: expectations.policy_digest.unwrap_or_default(),
286    };
287    let rules: Vec<AccessRule> = allowlist
288        .iter()
289        .map(|rule| AccessRule {
290            resource: rule.resource,
291            offset: rule.offset,
292            width: rule.width,
293            class: match rule.class {
294                flab::AccessClass::ReadOnce => AccessClass::ReadOnce,
295                flab::AccessClass::Snapshot => AccessClass::Snapshot,
296                flab::AccessClass::Write => AccessClass::Write,
297                flab::AccessClass::Poll => AccessClass::Poll,
298                flab::AccessClass::Sequence => AccessClass::Sequence,
299                flab::AccessClass::Protocol => AccessClass::Protocol,
300                flab::AccessClass::Interrupt => AccessClass::Interrupt,
301            },
302        })
303        .collect();
304
305    let mut state = state.inner.lock().unwrap();
306    let run_id = context.run_id.clone();
307    let result = state.sessions.open_session(context, mode, &expectations, rules);
308    let record = match &result {
309        Ok(id) => AuditRecord {
310            session: Some(*id),
311            resource: None,
312            operation: "open_session",
313            offset: None,
314            decision: Decision::Allowed,
315            status: OpStatus::Ok,
316            value: None,
317            timestamp_ns: now_ns(),
318            run_id: Some(run_id),
319            item_index: None,
320        },
321        Err(error) => {
322            // A rejected allowlist records the first offending rule, as
323            // the wire contract documents.
324            let (resource, offset) = match error {
325                OpenError::RejectedAllowlist { rule, .. } => {
326                    (Some(rule.resource), Some(rule.offset))
327                }
328                _ => (None, None),
329            };
330            AuditRecord {
331                session: None,
332                resource,
333                operation: "open_session",
334                offset,
335                decision: Decision::Denied(open_error_denial(error)),
336                status: OpStatus::Rejected,
337                value: None,
338                timestamp_ns: now_ns(),
339                run_id: Some(run_id),
340                item_index: None,
341            }
342        }
343    };
344    state.audit.append(record);
345    if let Ok(id) = &result {
346        if mode == SessionMode::Mutating {
347            let mut q_record = AuditRecord::lifecycle("quiesce_engaged", now_ns());
348            q_record.session = Some(*id);
349            state.audit.append(q_record);
350        }
351    }
352    result
353}
354
355/// Serves one `Proxy` connection, spawning a task per opened
356/// session on `scope`.
357pub async fn serve_proxy(
358    state: SharedState,
359    scope: ScopeHandle,
360    mut stream: flab::Proxy_RequestStream,
361) {
362    while let Ok(Some(request)) = stream.try_next().await {
363        match request {
364            flab::Proxy_Request::Describe { responder } => {
365                let description = describe(&state);
366                let _ = responder.send(&description);
367            }
368            flab::Proxy_Request::OpenSession {
369                context,
370                mode,
371                expectations,
372                allowlist,
373                session,
374                responder,
375            } => match open_session(&state, context, mode, expectations, allowlist) {
376                Ok(id) => {
377                    scope.spawn(serve_session(
378                        state.clone(),
379                        id,
380                        session.into_stream(),
381                        scope.clone(),
382                    ));
383                    let _ = responder.send(Ok(id));
384                }
385                Err(error) => {
386                    let _ = responder.send(Err(open_error_to_fidl(&error)));
387                }
388            },
389            flab::Proxy_Request::_UnknownMethod { .. } => {}
390        }
391    }
392}
393
394async fn serve_session(
395    state: SharedState,
396    id: u64,
397    mut stream: flab::SessionRequestStream,
398    scope: ScopeHandle,
399) {
400    while let Ok(Some(request)) = stream.try_next().await {
401        match request {
402            flab::SessionRequest::Read32 { resource, offset, responder } => {
403                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
404                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
405                    continue;
406                }
407                let result = {
408                    let guard = &mut *state.inner.lock().unwrap();
409                    let ProxyState { sessions, executor, audit, .. } = guard;
410                    let check = match sessions.session(id) {
411                        None => Err(flab::OperationError::StaleIdentity),
412                        Some(session) => session
413                            .policy
414                            .check_read32(resource, offset, AccessClass::ReadOnce)
415                            .map_err(denial_to_fidl),
416                    };
417                    match check {
418                        Err(flab::OperationError::StaleIdentity) => {
419                            Err(flab::OperationError::StaleIdentity)
420                        }
421                        Err(_) => {
422                            let session = sessions.session(id).unwrap();
423                            executor
424                                .read32(&session.policy, audit, id, resource, offset)
425                                .map(|outcome| {
426                                    (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
427                                })
428                                .map_err(|error| match error {
429                                    ReadError::Denied { denial, .. } => denial_to_fidl(denial),
430                                    ReadError::Backend { .. } => flab::OperationError::BackendFault,
431                                })
432                        }
433                        Ok(()) => {
434                            let now = now_ns();
435                            match sessions.check_access(id, AccessClass::ReadOnce, now) {
436                                Err(denial) => {
437                                    let record = AuditRecord {
438                                        session: Some(id),
439                                        resource: Some(resource),
440                                        operation: "read32",
441                                        offset: Some(offset),
442                                        decision: Decision::Denied(denial),
443                                        status: OpStatus::Rejected,
444                                        value: None,
445                                        timestamp_ns: now,
446                                        run_id: None,
447                                        item_index: None,
448                                    };
449                                    audit.append(record);
450                                    Err(denial_to_fidl(denial))
451                                }
452                                Ok(()) => {
453                                    let session = sessions.session(id).unwrap();
454                                    executor
455                                        .read32(&session.policy, audit, id, resource, offset)
456                                        .map(|outcome| {
457                                            (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
458                                        })
459                                        .map_err(|error| match error {
460                                            ReadError::Denied { denial, .. } => {
461                                                denial_to_fidl(denial)
462                                            }
463                                            ReadError::Backend { .. } => {
464                                                flab::OperationError::BackendFault
465                                            }
466                                        })
467                                }
468                            }
469                        }
470                    }
471                };
472                let _ = responder.send(result);
473            }
474            flab::SessionRequest::Snapshot { items, responder } => {
475                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
476                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
477                    continue;
478                }
479                let items: Vec<SnapshotItem> = items
480                    .iter()
481                    .map(|item| SnapshotItem { resource: item.resource, offset: item.offset })
482                    .collect();
483                let result = {
484                    let guard = &mut *state.inner.lock().unwrap();
485                    let ProxyState { sessions, executor, audit, .. } = guard;
486                    if sessions.session(id).is_none() {
487                        Err(flab::OperationError::StaleIdentity)
488                    } else {
489                        let now = now_ns();
490                        match sessions.check_access(id, AccessClass::Snapshot, now) {
491                            Err(denial) => {
492                                let record = AuditRecord {
493                                    session: Some(id),
494                                    resource: None,
495                                    operation: "snapshot",
496                                    offset: None,
497                                    decision: Decision::Denied(denial),
498                                    status: OpStatus::Rejected,
499                                    value: None,
500                                    timestamp_ns: now,
501                                    run_id: None,
502                                    item_index: None,
503                                };
504                                audit.append(record);
505                                Err(denial_to_fidl(denial))
506                            }
507                            Ok(()) => {
508                                let session = sessions.session(id).unwrap();
509                                executor
510                                    .snapshot(&session.policy, audit, id, &items)
511                                    .map(|outcome| {
512                                        let results: Vec<flab::SnapshotItemResult> = outcome
513                                            .results
514                                            .iter()
515                                            .map(|result| flab::SnapshotItemResult {
516                                                item: flab::SnapshotItem {
517                                                    resource: result.item.resource,
518                                                    offset: result.item.offset,
519                                                },
520                                                ok: result.value.is_ok(),
521                                                value: result.value.unwrap_or(0),
522                                                audit_seq: result.audit_seq,
523                                                timestamp_ns: result.timestamp_ns,
524                                            })
525                                            .collect();
526                                        (results, outcome.complete)
527                                    })
528                                    .map_err(|error| match error {
529                                        SnapshotError::TooManyItems { .. } => {
530                                            flab::OperationError::LimitExceeded
531                                        }
532                                        SnapshotError::Rejected { denial, .. } => {
533                                            denial_to_fidl(denial)
534                                        }
535                                    })
536                            }
537                        }
538                    }
539                };
540                let _ = responder.send(
541                    result
542                        .as_ref()
543                        .map(|(results, complete)| (results.as_slice(), *complete))
544                        .map_err(|error| *error),
545                );
546            }
547            flab::SessionRequest::Write32 {
548                resource,
549                offset,
550                value,
551                write_mask,
552                precondition,
553                readback,
554                responder,
555            } => {
556                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
557                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
558                    continue;
559                }
560                let precondition =
561                    precondition.map(|p| WritePrecondition { expected: p.expected, mask: p.mask });
562                let result = {
563                    let guard = &mut *state.inner.lock().unwrap();
564                    let ProxyState { sessions, executor, audit, .. } = guard;
565                    let check = match sessions.session(id) {
566                        None => Err(flab::OperationError::StaleIdentity),
567                        Some(session) => session
568                            .policy
569                            .check_write32(resource, offset, write_mask, precondition.as_ref())
570                            .map_err(denial_to_fidl),
571                    };
572                    match check {
573                        Err(flab::OperationError::StaleIdentity) => {
574                            Err(flab::OperationError::StaleIdentity)
575                        }
576                        Err(_) => {
577                            let session = sessions.session(id).unwrap();
578                            executor
579                                .write32(
580                                    &session.policy,
581                                    audit,
582                                    id,
583                                    resource,
584                                    offset,
585                                    value,
586                                    write_mask,
587                                    precondition,
588                                    readback,
589                                )
590                                .map(|outcome| {
591                                    (
592                                        outcome.readback_value,
593                                        outcome.audit_seq,
594                                        outcome.timestamp_ns,
595                                    )
596                                })
597                                .map_err(|error| match error {
598                                    WriteError::Denied { denial, .. } => denial_to_fidl(denial),
599                                    WriteError::Backend { .. } => {
600                                        flab::OperationError::BackendFault
601                                    }
602                                })
603                        }
604                        Ok(_) => {
605                            let now = now_ns();
606                            match sessions.check_access(id, AccessClass::Write, now) {
607                                Err(denial) => {
608                                    let record = AuditRecord {
609                                        session: Some(id),
610                                        resource: Some(resource),
611                                        operation: "write32",
612                                        offset: Some(offset),
613                                        decision: Decision::Denied(denial),
614                                        status: OpStatus::Rejected,
615                                        value: None,
616                                        timestamp_ns: now,
617                                        run_id: None,
618                                        item_index: None,
619                                    };
620                                    audit.append(record);
621                                    Err(denial_to_fidl(denial))
622                                }
623                                Ok(()) => {
624                                    let session = sessions.session(id).unwrap();
625                                    executor
626                                        .write32(
627                                            &session.policy,
628                                            audit,
629                                            id,
630                                            resource,
631                                            offset,
632                                            value,
633                                            write_mask,
634                                            precondition,
635                                            readback,
636                                        )
637                                        .map(|outcome| {
638                                            (
639                                                outcome.readback_value,
640                                                outcome.audit_seq,
641                                                outcome.timestamp_ns,
642                                            )
643                                        })
644                                        .map_err(|error| match error {
645                                            WriteError::Denied { denial, .. } => {
646                                                denial_to_fidl(denial)
647                                            }
648                                            WriteError::Backend { .. } => {
649                                                flab::OperationError::BackendFault
650                                            }
651                                        })
652                                }
653                            }
654                        }
655                    }
656                };
657                let _ = responder.send(result);
658            }
659            flab::SessionRequest::Poll32 {
660                resource,
661                offset,
662                expected,
663                mask,
664                interval_ns,
665                timeout_ns,
666                responder,
667            } => {
668                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
669                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
670                    continue;
671                }
672                let start_ts = now_ns();
673                let deadline = start_ts.saturating_add(timeout_ns);
674
675                // Initial lock: validate session and policy.
676                let initial_check = {
677                    let guard = &mut *state.inner.lock().unwrap();
678                    let ProxyState { sessions, audit, .. } = guard;
679                    match sessions.session(id) {
680                        None => Err(flab::OperationError::StaleIdentity),
681                        Some(session) => {
682                            match session.policy.check_poll32(
683                                resource,
684                                offset,
685                                mask,
686                                interval_ns,
687                                timeout_ns,
688                            ) {
689                                Ok(()) => {
690                                    if let Err(denial) = sessions.check_deadline(id, timeout_ns) {
691                                        let record = AuditRecord {
692                                            session: Some(id),
693                                            resource: Some(resource),
694                                            operation: "poll32",
695                                            offset: Some(offset),
696                                            decision: Decision::Denied(denial),
697                                            status: OpStatus::Rejected,
698                                            value: None,
699                                            timestamp_ns: now_ns(),
700                                            run_id: None,
701                                            item_index: None,
702                                        };
703                                        audit.append(record);
704                                        Err(denial_to_fidl(denial))
705                                    } else if let Err(denial) =
706                                        sessions.check_access(id, AccessClass::Poll, now_ns())
707                                    {
708                                        let record = AuditRecord {
709                                            session: Some(id),
710                                            resource: Some(resource),
711                                            operation: "poll32",
712                                            offset: Some(offset),
713                                            decision: Decision::Denied(denial),
714                                            status: OpStatus::Rejected,
715                                            value: None,
716                                            timestamp_ns: now_ns(),
717                                            run_id: None,
718                                            item_index: None,
719                                        };
720                                        audit.append(record);
721                                        Err(denial_to_fidl(denial))
722                                    } else {
723                                        Ok(())
724                                    }
725                                }
726                                Err(denial) => {
727                                    let record = AuditRecord {
728                                        session: Some(id),
729                                        resource: Some(resource),
730                                        operation: "poll32",
731                                        offset: Some(offset),
732                                        decision: Decision::Denied(denial),
733                                        status: OpStatus::Rejected,
734                                        value: None,
735                                        timestamp_ns: now_ns(),
736                                        run_id: None,
737                                        item_index: None,
738                                    };
739                                    audit.append(record);
740                                    Err(denial_to_fidl(denial))
741                                }
742                            }
743                        }
744                    }
745                };
746
747                if let Err(err) = initial_check {
748                    let _ = responder.send(Err(err));
749                    continue;
750                }
751
752                let mut last_val = None;
753                let poll_res = loop {
754                    if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
755                        break Err(flab::OperationError::NotAccepting);
756                    }
757                    // Lock to perform one read step
758                    let step_res = {
759                        let guard = &mut *state.inner.lock().unwrap();
760                        let ProxyState { sessions, executor, audit, .. } = guard;
761                        match sessions.session(id) {
762                            None => Err(flab::OperationError::StaleIdentity),
763                            Some(_) => match executor
764                                .poll32_read_step(audit, id, resource, offset, expected, mask, None)
765                            {
766                                Ok(Ok(outcome)) => Ok(Some(outcome)),
767                                Ok(Err(val)) => {
768                                    last_val = Some(val);
769                                    Ok(None)
770                                }
771                                Err(PollError::Denied { denial, .. }) => {
772                                    Err(denial_to_fidl(denial))
773                                }
774                                Err(PollError::Backend { .. }) => {
775                                    Err(flab::OperationError::BackendFault)
776                                }
777                            },
778                        }
779                    };
780
781                    match step_res {
782                        Err(err) => break Err(err),
783                        Ok(Some(outcome)) => {
784                            break Ok((outcome.value, outcome.audit_seq, outcome.timestamp_ns));
785                        }
786                        Ok(None) => {
787                            let now = now_ns();
788                            if now >= deadline {
789                                let guard = &mut *state.inner.lock().unwrap();
790                                let ProxyState { sessions, executor, audit, .. } = guard;
791                                if sessions.session(id).is_none() {
792                                    break Err(flab::OperationError::StaleIdentity);
793                                } else {
794                                    executor.poll32_timeout(
795                                        audit, id, resource, offset, last_val, None,
796                                    );
797                                    break Err(flab::OperationError::Timeout);
798                                }
799                            }
800                            let sleep_dur = if interval_ns > 0 {
801                                let rem = deadline.saturating_sub(now);
802                                interval_ns.min(rem)
803                            } else {
804                                0
805                            };
806                            if sleep_dur > 0 {
807                                fuchsia_async::Timer::new(zx::MonotonicInstant::after(
808                                    zx::Duration::from_nanos(sleep_dur),
809                                ))
810                                .await;
811                            } else {
812                                fuchsia_async::Timer::new(zx::MonotonicInstant::after(
813                                    zx::Duration::from_nanos(1000),
814                                ))
815                                .await;
816                            }
817                            if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
818                                break Err(flab::OperationError::NotAccepting);
819                            }
820                        }
821                    }
822                };
823
824                let _ = responder.send(poll_res);
825            }
826            flab::SessionRequest::ExecuteSequence { items, responder } => {
827                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
828                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
829                    continue;
830                }
831                let mut core_items = Vec::with_capacity(items.len());
832                let mut unknown_item_index = None;
833                for (idx, item) in items.iter().enumerate() {
834                    match fidl_to_core_sequence_item(item) {
835                        Some(core_item) => core_items.push(core_item),
836                        None => {
837                            unknown_item_index = Some(idx);
838                            break;
839                        }
840                    }
841                }
842
843                // Initial lock: whole-sequence prevalidation
844                let prevalidation = {
845                    let guard = &mut *state.inner.lock().unwrap();
846                    let ProxyState { sessions, executor, audit, .. } = guard;
847                    match sessions.session(id) {
848                        None => Err(flab::OperationError::StaleIdentity),
849                        Some(session) => {
850                            if let Some(idx) = unknown_item_index {
851                                let record = AuditRecord {
852                                    session: Some(id),
853                                    resource: None,
854                                    operation: "sequence",
855                                    offset: None,
856                                    decision: Decision::Denied(Denial::UnsupportedAccessClass),
857                                    status: OpStatus::Rejected,
858                                    value: None,
859                                    timestamp_ns: now_ns(),
860                                    run_id: None,
861                                    item_index: Some(idx as u32),
862                                };
863                                audit.append(record);
864                                Err(flab::OperationError::UnsupportedAccessClass)
865                            } else if core_items.len() > executor.limits().max_sequence_items {
866                                let record = AuditRecord {
867                                    session: Some(id),
868                                    resource: None,
869                                    operation: "sequence",
870                                    offset: None,
871                                    decision: Decision::Denied(Denial::LimitExceeded),
872                                    status: OpStatus::Rejected,
873                                    value: None,
874                                    timestamp_ns: now_ns(),
875                                    run_id: None,
876                                    item_index: None,
877                                };
878                                audit.append(record);
879                                Err(flab::OperationError::LimitExceeded)
880                            } else {
881                                match executor.prevalidate_sequence(&session.policy, &core_items) {
882                                    Ok(()) => {
883                                        let now = now_ns();
884                                        match sessions.check_access(id, AccessClass::Sequence, now)
885                                        {
886                                            Err(denial) => {
887                                                let record = AuditRecord {
888                                                    session: Some(id),
889                                                    resource: None,
890                                                    operation: "sequence",
891                                                    offset: None,
892                                                    decision: Decision::Denied(denial),
893                                                    status: OpStatus::Rejected,
894                                                    value: None,
895                                                    timestamp_ns: now,
896                                                    run_id: None,
897                                                    item_index: None,
898                                                };
899                                                audit.append(record);
900                                                Err(denial_to_fidl(denial))
901                                            }
902                                            Ok(()) => Ok(()),
903                                        }
904                                    }
905                                    Err((idx, denial)) => {
906                                        let record = AuditRecord {
907                                            session: Some(id),
908                                            resource: None,
909                                            operation: "sequence",
910                                            offset: None,
911                                            decision: Decision::Denied(denial),
912                                            status: OpStatus::Rejected,
913                                            value: None,
914                                            timestamp_ns: now_ns(),
915                                            run_id: None,
916                                            item_index: Some(idx as u32),
917                                        };
918                                        audit.append(record);
919                                        Err(denial_to_fidl(denial))
920                                    }
921                                }
922                            }
923                        }
924                    }
925                };
926
927                if let Err(err) = prevalidation {
928                    let _ = responder.send(Err(err));
929                    continue;
930                }
931
932                // Sequence execution loop
933                let seq_start_ts = now_ns();
934                let mut results = Vec::with_capacity(core_items.len());
935                let mut complete = true;
936
937                for (index, item) in core_items.iter().enumerate() {
938                    let idx = index as u32;
939
940                    if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
941                        results.push(flab::SequenceItemResult {
942                            index: idx,
943                            ok: false,
944                            outcome: flab::SequenceItemOutcome::Error(
945                                flab::OperationError::NotAccepting,
946                            ),
947                        });
948                        complete = false;
949                        break;
950                    }
951
952                    let max_sequence_duration = {
953                        let guard = state.inner.lock().unwrap();
954                        guard.config.max_sequence_duration_ns as i64
955                    };
956                    if now_ns().saturating_sub(seq_start_ts) > max_sequence_duration {
957                        let guard = &mut *state.inner.lock().unwrap();
958                        let ProxyState { audit, .. } = guard;
959                        let record = AuditRecord {
960                            session: Some(id),
961                            resource: None,
962                            operation: "sequence",
963                            offset: None,
964                            decision: Decision::Denied(Denial::Timeout),
965                            status: OpStatus::Rejected,
966                            value: None,
967                            timestamp_ns: now_ns(),
968                            run_id: None,
969                            item_index: Some(idx),
970                        };
971                        audit.append(record);
972                        results.push(flab::SequenceItemResult {
973                            index: idx,
974                            ok: false,
975                            outcome: flab::SequenceItemOutcome::Error(
976                                flab::OperationError::Timeout,
977                            ),
978                        });
979                        complete = false;
980                        break;
981                    }
982
983                    match item {
984                        CoreSequenceItem::Read32 { resource, offset } => {
985                            let step = {
986                                let guard = &mut *state.inner.lock().unwrap();
987                                let ProxyState { sessions, executor, audit, .. } = guard;
988                                match sessions.session(id) {
989                                    None => Err(flab::OperationError::StaleIdentity),
990                                    Some(session) => match executor.read32_internal(
991                                        &session.policy,
992                                        audit,
993                                        id,
994                                        *resource,
995                                        *offset,
996                                        Some(idx),
997                                    ) {
998                                        Ok(outcome) => Ok(flab::SequenceItemResult {
999                                            index: idx,
1000                                            ok: true,
1001                                            outcome: flab::SequenceItemOutcome::Read32(
1002                                                flab::ReadResult {
1003                                                    value: outcome.value,
1004                                                    audit_seq: outcome.audit_seq,
1005                                                    timestamp_ns: outcome.timestamp_ns,
1006                                                },
1007                                            ),
1008                                        }),
1009                                        Err(ReadError::Denied { denial, .. }) => {
1010                                            Err(denial_to_fidl(denial))
1011                                        }
1012                                        Err(ReadError::Backend { .. }) => {
1013                                            Err(flab::OperationError::BackendFault)
1014                                        }
1015                                    },
1016                                }
1017                            };
1018                            match step {
1019                                Ok(res) => results.push(res),
1020                                Err(err) => {
1021                                    results.push(flab::SequenceItemResult {
1022                                        index: idx,
1023                                        ok: false,
1024                                        outcome: flab::SequenceItemOutcome::Error(err),
1025                                    });
1026                                    complete = false;
1027                                    break;
1028                                }
1029                            }
1030                        }
1031                        CoreSequenceItem::Write32 {
1032                            resource,
1033                            offset,
1034                            value,
1035                            write_mask,
1036                            precondition,
1037                            readback,
1038                        } => {
1039                            let step = {
1040                                let guard = &mut *state.inner.lock().unwrap();
1041                                let ProxyState { sessions, executor, audit, .. } = guard;
1042                                match sessions.session(id) {
1043                                    None => Err(flab::OperationError::StaleIdentity),
1044                                    Some(session) => match executor.write32_internal(
1045                                        &session.policy,
1046                                        audit,
1047                                        id,
1048                                        *resource,
1049                                        *offset,
1050                                        *value,
1051                                        *write_mask,
1052                                        *precondition,
1053                                        *readback,
1054                                        Some(idx),
1055                                    ) {
1056                                        Ok(outcome) => Ok(flab::SequenceItemResult {
1057                                            index: idx,
1058                                            ok: true,
1059                                            outcome: flab::SequenceItemOutcome::Write32(
1060                                                flab::WriteResult {
1061                                                    readback_value: outcome.readback_value,
1062                                                    audit_seq: outcome.audit_seq,
1063                                                    timestamp_ns: outcome.timestamp_ns,
1064                                                },
1065                                            ),
1066                                        }),
1067                                        Err(WriteError::Denied { denial, .. }) => {
1068                                            Err(denial_to_fidl(denial))
1069                                        }
1070                                        Err(WriteError::Backend { .. }) => {
1071                                            Err(flab::OperationError::BackendFault)
1072                                        }
1073                                    },
1074                                }
1075                            };
1076                            match step {
1077                                Ok(res) => results.push(res),
1078                                Err(err) => {
1079                                    results.push(flab::SequenceItemResult {
1080                                        index: idx,
1081                                        ok: false,
1082                                        outcome: flab::SequenceItemOutcome::Error(err),
1083                                    });
1084                                    complete = false;
1085                                    break;
1086                                }
1087                            }
1088                        }
1089                        CoreSequenceItem::Barrier => {
1090                            let step = {
1091                                let guard = &mut *state.inner.lock().unwrap();
1092                                let ProxyState { sessions, executor, audit, .. } = guard;
1093                                match sessions.session(id) {
1094                                    None => Err(flab::OperationError::StaleIdentity),
1095                                    Some(_) => {
1096                                        let ts = now_ns();
1097                                        executor.barrier();
1098                                        let record = AuditRecord {
1099                                            session: Some(id),
1100                                            resource: None,
1101                                            operation: "barrier",
1102                                            offset: None,
1103                                            decision: Decision::Allowed,
1104                                            status: OpStatus::Ok,
1105                                            value: None,
1106                                            timestamp_ns: ts,
1107                                            run_id: None,
1108                                            item_index: Some(idx),
1109                                        };
1110                                        audit.append(record);
1111                                        Ok(flab::SequenceItemResult {
1112                                            index: idx,
1113                                            ok: true,
1114                                            outcome: flab::SequenceItemOutcome::Barrier(
1115                                                flab::Barrier,
1116                                            ),
1117                                        })
1118                                    }
1119                                }
1120                            };
1121                            match step {
1122                                Ok(res) => results.push(res),
1123                                Err(err) => {
1124                                    results.push(flab::SequenceItemResult {
1125                                        index: idx,
1126                                        ok: false,
1127                                        outcome: flab::SequenceItemOutcome::Error(err),
1128                                    });
1129                                    complete = false;
1130                                    break;
1131                                }
1132                            }
1133                        }
1134                        CoreSequenceItem::DelayNs(delay_ns) => {
1135                            if *delay_ns > 0 {
1136                                fuchsia_async::Timer::new(zx::MonotonicInstant::after(
1137                                    zx::Duration::from_nanos(*delay_ns),
1138                                ))
1139                                .await;
1140                            }
1141                            if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1142                                results.push(flab::SequenceItemResult {
1143                                    index: idx,
1144                                    ok: false,
1145                                    outcome: flab::SequenceItemOutcome::Error(
1146                                        flab::OperationError::NotAccepting,
1147                                    ),
1148                                });
1149                                complete = false;
1150                                break;
1151                            }
1152                            let step = {
1153                                let guard = &mut *state.inner.lock().unwrap();
1154                                let ProxyState { sessions, audit, .. } = guard;
1155                                match sessions.session(id) {
1156                                    None => Err(flab::OperationError::StaleIdentity),
1157                                    Some(_) => {
1158                                        let ts = now_ns();
1159                                        let record = AuditRecord {
1160                                            session: Some(id),
1161                                            resource: None,
1162                                            operation: "delay",
1163                                            offset: None,
1164                                            decision: Decision::Allowed,
1165                                            status: OpStatus::Ok,
1166                                            value: None,
1167                                            timestamp_ns: ts,
1168                                            run_id: None,
1169                                            item_index: Some(idx),
1170                                        };
1171                                        audit.append(record);
1172                                        Ok(flab::SequenceItemResult {
1173                                            index: idx,
1174                                            ok: true,
1175                                            outcome: flab::SequenceItemOutcome::DelayNs(
1176                                                flab::DelayNs,
1177                                            ),
1178                                        })
1179                                    }
1180                                }
1181                            };
1182                            match step {
1183                                Ok(res) => results.push(res),
1184                                Err(err) => {
1185                                    results.push(flab::SequenceItemResult {
1186                                        index: idx,
1187                                        ok: false,
1188                                        outcome: flab::SequenceItemOutcome::Error(err),
1189                                    });
1190                                    complete = false;
1191                                    break;
1192                                }
1193                            }
1194                        }
1195                        CoreSequenceItem::Poll32 {
1196                            resource,
1197                            offset,
1198                            expected,
1199                            mask,
1200                            interval_ns,
1201                            timeout_ns,
1202                        } => {
1203                            let start_ts = now_ns();
1204                            let deadline = start_ts.saturating_add(*timeout_ns);
1205                            let mut last_val = None;
1206                            let poll_res = loop {
1207                                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1208                                    break Err(flab::OperationError::NotAccepting);
1209                                }
1210                                if now_ns().saturating_sub(seq_start_ts) > max_sequence_duration {
1211                                    let guard = &mut *state.inner.lock().unwrap();
1212                                    let ProxyState { sessions, executor, audit, .. } = guard;
1213                                    if sessions.session(id).is_none() {
1214                                        break Err(flab::OperationError::StaleIdentity);
1215                                    } else {
1216                                        executor.poll32_timeout(
1217                                            audit,
1218                                            id,
1219                                            *resource,
1220                                            *offset,
1221                                            last_val,
1222                                            Some(idx),
1223                                        );
1224                                        break Err(flab::OperationError::Timeout);
1225                                    }
1226                                }
1227                                let step = {
1228                                    let guard = &mut *state.inner.lock().unwrap();
1229                                    let ProxyState { sessions, executor, audit, .. } = guard;
1230                                    match sessions.session(id) {
1231                                        None => Err(flab::OperationError::StaleIdentity),
1232                                        Some(_) => match executor.poll32_read_step(
1233                                            audit,
1234                                            id,
1235                                            *resource,
1236                                            *offset,
1237                                            *expected,
1238                                            *mask,
1239                                            Some(idx),
1240                                        ) {
1241                                            Ok(Ok(outcome)) => Ok(Some(outcome)),
1242                                            Ok(Err(val)) => {
1243                                                last_val = Some(val);
1244                                                Ok(None)
1245                                            }
1246                                            Err(PollError::Denied { denial, .. }) => {
1247                                                Err(denial_to_fidl(denial))
1248                                            }
1249                                            Err(PollError::Backend { .. }) => {
1250                                                Err(flab::OperationError::BackendFault)
1251                                            }
1252                                        },
1253                                    }
1254                                };
1255                                match step {
1256                                    Err(err) => break Err(err),
1257                                    Ok(Some(outcome)) => {
1258                                        break Ok(flab::SequenceItemResult {
1259                                            index: idx,
1260                                            ok: true,
1261                                            outcome: flab::SequenceItemOutcome::Poll32(
1262                                                flab::PollResult {
1263                                                    value: outcome.value,
1264                                                    audit_seq: outcome.audit_seq,
1265                                                    timestamp_ns: outcome.timestamp_ns,
1266                                                },
1267                                            ),
1268                                        });
1269                                    }
1270                                    Ok(None) => {
1271                                        let now = now_ns();
1272                                        if now >= deadline {
1273                                            let guard = &mut *state.inner.lock().unwrap();
1274                                            let ProxyState { sessions, executor, audit, .. } =
1275                                                guard;
1276                                            if sessions.session(id).is_none() {
1277                                                break Err(flab::OperationError::StaleIdentity);
1278                                            } else {
1279                                                executor.poll32_timeout(
1280                                                    audit,
1281                                                    id,
1282                                                    *resource,
1283                                                    *offset,
1284                                                    last_val,
1285                                                    Some(idx),
1286                                                );
1287                                                break Err(flab::OperationError::Timeout);
1288                                            }
1289                                        }
1290                                        let sleep_dur = if *interval_ns > 0 {
1291                                            let rem = deadline.saturating_sub(now);
1292                                            (*interval_ns).min(rem)
1293                                        } else {
1294                                            0
1295                                        };
1296                                        if sleep_dur > 0 {
1297                                            fuchsia_async::Timer::new(zx::MonotonicInstant::after(
1298                                                zx::Duration::from_nanos(sleep_dur),
1299                                            ))
1300                                            .await;
1301                                        } else {
1302                                            fuchsia_async::Timer::new(zx::MonotonicInstant::after(
1303                                                zx::Duration::from_nanos(1000),
1304                                            ))
1305                                            .await;
1306                                        }
1307                                        if state
1308                                            .abort_token
1309                                            .load(std::sync::atomic::Ordering::SeqCst)
1310                                        {
1311                                            break Err(flab::OperationError::NotAccepting);
1312                                        }
1313                                    }
1314                                }
1315                            };
1316                            match poll_res {
1317                                Ok(res) => results.push(res),
1318                                Err(err) => {
1319                                    results.push(flab::SequenceItemResult {
1320                                        index: idx,
1321                                        ok: false,
1322                                        outcome: flab::SequenceItemOutcome::Error(err),
1323                                    });
1324                                    complete = false;
1325                                    break;
1326                                }
1327                            }
1328                        }
1329                        CoreSequenceItem::GpioRead { resource } => {
1330                            let step = {
1331                                let guard = &mut *state.inner.lock().unwrap();
1332                                let ProxyState { sessions, executor, audit, .. } = guard;
1333                                match sessions.session(id) {
1334                                    None => Err(flab::OperationError::StaleIdentity),
1335                                    Some(session) => match executor.gpio_read_internal(
1336                                        &session.policy,
1337                                        audit,
1338                                        id,
1339                                        *resource,
1340                                        Some(idx),
1341                                    ) {
1342                                        Ok(outcome) => Ok(flab::SequenceItemResult {
1343                                            index: idx,
1344                                            ok: true,
1345                                            outcome: flab::SequenceItemOutcome::GpioRead(
1346                                                flab::GpioReadResult {
1347                                                    value: outcome.value,
1348                                                    audit_seq: outcome.audit_seq,
1349                                                    timestamp_ns: outcome.timestamp_ns,
1350                                                },
1351                                            ),
1352                                        }),
1353                                        Err(GpioReadError::Denied { denial, .. }) => {
1354                                            Err(denial_to_fidl(denial))
1355                                        }
1356                                        Err(GpioReadError::Backend { .. }) => {
1357                                            Err(flab::OperationError::BackendFault)
1358                                        }
1359                                    },
1360                                }
1361                            };
1362                            match step {
1363                                Ok(res) => results.push(res),
1364                                Err(err) => {
1365                                    results.push(flab::SequenceItemResult {
1366                                        index: idx,
1367                                        ok: false,
1368                                        outcome: flab::SequenceItemOutcome::Error(err),
1369                                    });
1370                                    complete = false;
1371                                    break;
1372                                }
1373                            }
1374                        }
1375                        CoreSequenceItem::GpioWrite { resource, value } => {
1376                            let step = {
1377                                let guard = &mut *state.inner.lock().unwrap();
1378                                let ProxyState { sessions, executor, audit, .. } = guard;
1379                                match sessions.session(id) {
1380                                    None => Err(flab::OperationError::StaleIdentity),
1381                                    Some(session) => match executor.gpio_write_internal(
1382                                        &session.policy,
1383                                        audit,
1384                                        id,
1385                                        *resource,
1386                                        *value,
1387                                        Some(idx),
1388                                    ) {
1389                                        Ok(outcome) => Ok(flab::SequenceItemResult {
1390                                            index: idx,
1391                                            ok: true,
1392                                            outcome: flab::SequenceItemOutcome::GpioWrite(
1393                                                flab::GpioWriteResult {
1394                                                    audit_seq: outcome.audit_seq,
1395                                                    timestamp_ns: outcome.timestamp_ns,
1396                                                },
1397                                            ),
1398                                        }),
1399                                        Err(GpioWriteError::Denied { denial, .. }) => {
1400                                            Err(denial_to_fidl(denial))
1401                                        }
1402                                        Err(GpioWriteError::Backend { .. }) => {
1403                                            Err(flab::OperationError::BackendFault)
1404                                        }
1405                                    },
1406                                }
1407                            };
1408                            match step {
1409                                Ok(res) => results.push(res),
1410                                Err(err) => {
1411                                    results.push(flab::SequenceItemResult {
1412                                        index: idx,
1413                                        ok: false,
1414                                        outcome: flab::SequenceItemOutcome::Error(err),
1415                                    });
1416                                    complete = false;
1417                                    break;
1418                                }
1419                            }
1420                        }
1421                        CoreSequenceItem::I2cTransfer { resource, write_data, read_length } => {
1422                            let step = {
1423                                let guard = &mut *state.inner.lock().unwrap();
1424                                let ProxyState { sessions, executor, audit, .. } = guard;
1425                                match sessions.session(id) {
1426                                    None => Err(flab::OperationError::StaleIdentity),
1427                                    Some(session) => match executor.i2c_transfer_internal(
1428                                        &session.policy,
1429                                        audit,
1430                                        id,
1431                                        *resource,
1432                                        write_data,
1433                                        *read_length,
1434                                        Some(idx),
1435                                    ) {
1436                                        Ok(outcome) => Ok(flab::SequenceItemResult {
1437                                            index: idx,
1438                                            ok: true,
1439                                            outcome: flab::SequenceItemOutcome::I2cTransfer(
1440                                                flab::I2cTransferResult {
1441                                                    read_data: outcome.read_data,
1442                                                    audit_seq: outcome.audit_seq,
1443                                                    timestamp_ns: outcome.timestamp_ns,
1444                                                },
1445                                            ),
1446                                        }),
1447                                        Err(I2cTransferError::Denied { denial, .. }) => {
1448                                            Err(denial_to_fidl(denial))
1449                                        }
1450                                        Err(I2cTransferError::Backend { .. }) => {
1451                                            Err(flab::OperationError::BackendFault)
1452                                        }
1453                                    },
1454                                }
1455                            };
1456                            match step {
1457                                Ok(res) => results.push(res),
1458                                Err(err) => {
1459                                    results.push(flab::SequenceItemResult {
1460                                        index: idx,
1461                                        ok: false,
1462                                        outcome: flab::SequenceItemOutcome::Error(err),
1463                                    });
1464                                    complete = false;
1465                                    break;
1466                                }
1467                            }
1468                        }
1469                        CoreSequenceItem::SpiTransmit { resource, tx_data } => {
1470                            let step = {
1471                                let guard = &mut *state.inner.lock().unwrap();
1472                                let ProxyState { sessions, executor, audit, .. } = guard;
1473                                match sessions.session(id) {
1474                                    None => Err(flab::OperationError::StaleIdentity),
1475                                    Some(session) => match executor.spi_transmit_internal(
1476                                        &session.policy,
1477                                        audit,
1478                                        id,
1479                                        *resource,
1480                                        tx_data,
1481                                        Some(idx),
1482                                    ) {
1483                                        Ok(outcome) => Ok(flab::SequenceItemResult {
1484                                            index: idx,
1485                                            ok: true,
1486                                            outcome: flab::SequenceItemOutcome::SpiTransmit(
1487                                                flab::SpiTransmitResult {
1488                                                    rx_data: outcome.rx_data,
1489                                                    audit_seq: outcome.audit_seq,
1490                                                    timestamp_ns: outcome.timestamp_ns,
1491                                                },
1492                                            ),
1493                                        }),
1494                                        Err(SpiTransmitError::Denied { denial, .. }) => {
1495                                            Err(denial_to_fidl(denial))
1496                                        }
1497                                        Err(SpiTransmitError::Backend { .. }) => {
1498                                            Err(flab::OperationError::BackendFault)
1499                                        }
1500                                    },
1501                                }
1502                            };
1503                            match step {
1504                                Ok(res) => results.push(res),
1505                                Err(err) => {
1506                                    results.push(flab::SequenceItemResult {
1507                                        index: idx,
1508                                        ok: false,
1509                                        outcome: flab::SequenceItemOutcome::Error(err),
1510                                    });
1511                                    complete = false;
1512                                    break;
1513                                }
1514                            }
1515                        }
1516                    }
1517                }
1518
1519                let _ = responder.send(Ok((results.as_slice(), complete)));
1520            }
1521            flab::SessionRequest::ReadAudit { cursor, limit, responder } => {
1522                let (page, boot_id, proxy_generation) = {
1523                    let state = state.inner.lock().unwrap();
1524                    let limit = (limit.min(flab::MAX_AUDIT_PAGE_ENTRIES)) as usize;
1525                    let identity = state.sessions.identity();
1526                    (
1527                        state.audit.read(cursor, limit),
1528                        identity.boot_id.clone(),
1529                        identity.proxy_generation,
1530                    )
1531                };
1532                let entries: Vec<flab::AuditEntry> = page
1533                    .entries
1534                    .iter()
1535                    .map(|entry| flab::AuditEntry {
1536                        seq: Some(entry.seq),
1537                        session: entry.record.session,
1538                        resource: entry.record.resource,
1539                        operation: Some(entry.record.operation.to_string()),
1540                        offset: entry.record.offset,
1541                        decision: Some(match entry.record.decision {
1542                            Decision::Allowed => flab::AuditDecision::Allowed,
1543                            Decision::Denied(_) => flab::AuditDecision::Denied,
1544                        }),
1545                        denial: match entry.record.decision {
1546                            Decision::Allowed => None,
1547                            Decision::Denied(denial) => Some(denial_to_fidl(denial)),
1548                        },
1549                        status: Some(match entry.record.status {
1550                            OpStatus::Ok => flab::AuditStatus::Ok,
1551                            OpStatus::Rejected => flab::AuditStatus::Rejected,
1552                            OpStatus::BackendFault => flab::AuditStatus::BackendFault,
1553                        }),
1554                        value: entry.record.value,
1555                        timestamp_ns: Some(entry.record.timestamp_ns),
1556                        run_id: entry.record.run_id.clone(),
1557                        item_index: entry.record.item_index,
1558                        proxy_generation: Some(proxy_generation),
1559                        boot_id: Some(boot_id.clone()),
1560                        ..Default::default()
1561                    })
1562                    .collect();
1563                let _ = responder.send(
1564                    &entries,
1565                    page.oldest_retained.is_some(),
1566                    page.oldest_retained.unwrap_or(0),
1567                    page.next_cursor,
1568                );
1569            }
1570            flab::SessionRequest::GpioRead { resource, responder } => {
1571                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1572                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
1573                    continue;
1574                }
1575                let result = {
1576                    let guard = &mut *state.inner.lock().unwrap();
1577                    let ProxyState { sessions, executor, audit, .. } = guard;
1578                    let check = match sessions.session(id) {
1579                        None => Err(flab::OperationError::StaleIdentity),
1580                        Some(session) => {
1581                            session.policy.check_gpio_read(resource).map_err(denial_to_fidl)
1582                        }
1583                    };
1584                    match check {
1585                        Err(flab::OperationError::StaleIdentity) => {
1586                            Err(flab::OperationError::StaleIdentity)
1587                        }
1588                        Err(_) => {
1589                            let session = sessions.session(id).unwrap();
1590                            executor
1591                                .gpio_read(&session.policy, audit, id, resource)
1592                                .map(|outcome| {
1593                                    (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
1594                                })
1595                                .map_err(|error| match error {
1596                                    GpioReadError::Denied { denial, .. } => denial_to_fidl(denial),
1597                                    GpioReadError::Backend { .. } => {
1598                                        flab::OperationError::BackendFault
1599                                    }
1600                                })
1601                        }
1602                        Ok(_) => {
1603                            let now = now_ns();
1604                            match sessions.check_access(id, AccessClass::Protocol, now) {
1605                                Err(denial) => {
1606                                    let record = AuditRecord {
1607                                        session: Some(id),
1608                                        resource: Some(resource),
1609                                        operation: "gpio_read",
1610                                        offset: None,
1611                                        decision: Decision::Denied(denial),
1612                                        status: OpStatus::Rejected,
1613                                        value: None,
1614                                        timestamp_ns: now,
1615                                        run_id: None,
1616                                        item_index: None,
1617                                    };
1618                                    audit.append(record);
1619                                    Err(denial_to_fidl(denial))
1620                                }
1621                                Ok(()) => {
1622                                    let session = sessions.session(id).unwrap();
1623                                    executor
1624                                        .gpio_read(&session.policy, audit, id, resource)
1625                                        .map(|outcome| {
1626                                            (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
1627                                        })
1628                                        .map_err(|error| match error {
1629                                            GpioReadError::Denied { denial, .. } => {
1630                                                denial_to_fidl(denial)
1631                                            }
1632                                            GpioReadError::Backend { .. } => {
1633                                                flab::OperationError::BackendFault
1634                                            }
1635                                        })
1636                                }
1637                            }
1638                        }
1639                    }
1640                };
1641                let _ = responder.send(result);
1642            }
1643            flab::SessionRequest::GpioWrite { resource, value, responder } => {
1644                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1645                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
1646                    continue;
1647                }
1648                let result = {
1649                    let guard = &mut *state.inner.lock().unwrap();
1650                    let ProxyState { sessions, executor, audit, .. } = guard;
1651                    let check = match sessions.session(id) {
1652                        None => Err(flab::OperationError::StaleIdentity),
1653                        Some(session) => {
1654                            session.policy.check_gpio_write(resource).map_err(denial_to_fidl)
1655                        }
1656                    };
1657                    match check {
1658                        Err(flab::OperationError::StaleIdentity) => {
1659                            Err(flab::OperationError::StaleIdentity)
1660                        }
1661                        Err(_) => {
1662                            let session = sessions.session(id).unwrap();
1663                            executor
1664                                .gpio_write(&session.policy, audit, id, resource, value)
1665                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
1666                                .map_err(|error| match error {
1667                                    GpioWriteError::Denied { denial, .. } => denial_to_fidl(denial),
1668                                    GpioWriteError::Backend { .. } => {
1669                                        flab::OperationError::BackendFault
1670                                    }
1671                                })
1672                        }
1673                        Ok(_) => {
1674                            let now = now_ns();
1675                            match sessions.check_access(id, AccessClass::Protocol, now) {
1676                                Err(denial) => {
1677                                    let record = AuditRecord {
1678                                        session: Some(id),
1679                                        resource: Some(resource),
1680                                        operation: "gpio_write",
1681                                        offset: None,
1682                                        decision: Decision::Denied(denial),
1683                                        status: OpStatus::Rejected,
1684                                        value: None,
1685                                        timestamp_ns: now,
1686                                        run_id: None,
1687                                        item_index: None,
1688                                    };
1689                                    audit.append(record);
1690                                    Err(denial_to_fidl(denial))
1691                                }
1692                                Ok(()) => {
1693                                    let session = sessions.session(id).unwrap();
1694                                    executor
1695                                        .gpio_write(&session.policy, audit, id, resource, value)
1696                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
1697                                        .map_err(|error| match error {
1698                                            GpioWriteError::Denied { denial, .. } => {
1699                                                denial_to_fidl(denial)
1700                                            }
1701                                            GpioWriteError::Backend { .. } => {
1702                                                flab::OperationError::BackendFault
1703                                            }
1704                                        })
1705                                }
1706                            }
1707                        }
1708                    }
1709                };
1710                let _ = responder.send(result);
1711            }
1712            flab::SessionRequest::I2cTransfer { resource, write_data, read_length, responder } => {
1713                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1714                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
1715                    continue;
1716                }
1717                let result = {
1718                    let guard = &mut *state.inner.lock().unwrap();
1719                    let ProxyState { sessions, executor, audit, .. } = guard;
1720                    let check = match sessions.session(id) {
1721                        None => Err(flab::OperationError::StaleIdentity),
1722                        Some(session) => session
1723                            .policy
1724                            .check_i2c_transfer(resource, write_data.len(), read_length as usize)
1725                            .map_err(denial_to_fidl),
1726                    };
1727                    match check {
1728                        Err(flab::OperationError::StaleIdentity) => {
1729                            Err(flab::OperationError::StaleIdentity)
1730                        }
1731                        Err(_) => {
1732                            let session = sessions.session(id).unwrap();
1733                            executor
1734                                .i2c_transfer(
1735                                    &session.policy,
1736                                    audit,
1737                                    id,
1738                                    resource,
1739                                    &write_data,
1740                                    read_length,
1741                                )
1742                                .map(|outcome| {
1743                                    (outcome.read_data, outcome.audit_seq, outcome.timestamp_ns)
1744                                })
1745                                .map_err(|error| match error {
1746                                    I2cTransferError::Denied { denial, .. } => {
1747                                        denial_to_fidl(denial)
1748                                    }
1749                                    I2cTransferError::Backend { .. } => {
1750                                        flab::OperationError::BackendFault
1751                                    }
1752                                })
1753                        }
1754                        Ok(_) => {
1755                            let now = now_ns();
1756                            match sessions.check_access(id, AccessClass::Protocol, now) {
1757                                Err(denial) => {
1758                                    let record = AuditRecord {
1759                                        session: Some(id),
1760                                        resource: Some(resource),
1761                                        operation: "i2c_transfer",
1762                                        offset: None,
1763                                        decision: Decision::Denied(denial),
1764                                        status: OpStatus::Rejected,
1765                                        value: None,
1766                                        timestamp_ns: now,
1767                                        run_id: None,
1768                                        item_index: None,
1769                                    };
1770                                    audit.append(record);
1771                                    Err(denial_to_fidl(denial))
1772                                }
1773                                Ok(()) => {
1774                                    let session = sessions.session(id).unwrap();
1775                                    executor
1776                                        .i2c_transfer(
1777                                            &session.policy,
1778                                            audit,
1779                                            id,
1780                                            resource,
1781                                            &write_data,
1782                                            read_length,
1783                                        )
1784                                        .map(|outcome| {
1785                                            (
1786                                                outcome.read_data,
1787                                                outcome.audit_seq,
1788                                                outcome.timestamp_ns,
1789                                            )
1790                                        })
1791                                        .map_err(|error| match error {
1792                                            I2cTransferError::Denied { denial, .. } => {
1793                                                denial_to_fidl(denial)
1794                                            }
1795                                            I2cTransferError::Backend { .. } => {
1796                                                flab::OperationError::BackendFault
1797                                            }
1798                                        })
1799                                }
1800                            }
1801                        }
1802                    }
1803                };
1804                let _ = responder.send(
1805                    result
1806                        .as_ref()
1807                        .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
1808                        .map_err(|err| *err),
1809                );
1810            }
1811            flab::SessionRequest::SpiTransmit { resource, tx_data, responder } => {
1812                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1813                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
1814                    continue;
1815                }
1816                let result = {
1817                    let guard = &mut *state.inner.lock().unwrap();
1818                    let ProxyState { sessions, executor, audit, .. } = guard;
1819                    let check = match sessions.session(id) {
1820                        None => Err(flab::OperationError::StaleIdentity),
1821                        Some(session) => session
1822                            .policy
1823                            .check_spi_transmit(resource, tx_data.len())
1824                            .map_err(denial_to_fidl),
1825                    };
1826                    match check {
1827                        Err(flab::OperationError::StaleIdentity) => {
1828                            Err(flab::OperationError::StaleIdentity)
1829                        }
1830                        Err(_) => {
1831                            let session = sessions.session(id).unwrap();
1832                            executor
1833                                .spi_transmit(&session.policy, audit, id, resource, &tx_data)
1834                                .map(|outcome| {
1835                                    (outcome.rx_data, outcome.audit_seq, outcome.timestamp_ns)
1836                                })
1837                                .map_err(|error| match error {
1838                                    SpiTransmitError::Denied { denial, .. } => {
1839                                        denial_to_fidl(denial)
1840                                    }
1841                                    SpiTransmitError::Backend { .. } => {
1842                                        flab::OperationError::BackendFault
1843                                    }
1844                                })
1845                        }
1846                        Ok(_) => {
1847                            let now = now_ns();
1848                            match sessions.check_access(id, AccessClass::Protocol, now) {
1849                                Err(denial) => {
1850                                    let record = AuditRecord {
1851                                        session: Some(id),
1852                                        resource: Some(resource),
1853                                        operation: "spi_transmit",
1854                                        offset: None,
1855                                        decision: Decision::Denied(denial),
1856                                        status: OpStatus::Rejected,
1857                                        value: None,
1858                                        timestamp_ns: now,
1859                                        run_id: None,
1860                                        item_index: None,
1861                                    };
1862                                    audit.append(record);
1863                                    Err(denial_to_fidl(denial))
1864                                }
1865                                Ok(()) => {
1866                                    let session = sessions.session(id).unwrap();
1867                                    executor
1868                                        .spi_transmit(
1869                                            &session.policy,
1870                                            audit,
1871                                            id,
1872                                            resource,
1873                                            &tx_data,
1874                                        )
1875                                        .map(|outcome| {
1876                                            (
1877                                                outcome.rx_data,
1878                                                outcome.audit_seq,
1879                                                outcome.timestamp_ns,
1880                                            )
1881                                        })
1882                                        .map_err(|error| match error {
1883                                            SpiTransmitError::Denied { denial, .. } => {
1884                                                denial_to_fidl(denial)
1885                                            }
1886                                            SpiTransmitError::Backend { .. } => {
1887                                                flab::OperationError::BackendFault
1888                                            }
1889                                        })
1890                                }
1891                            }
1892                        }
1893                    }
1894                };
1895                let _ = responder.send(
1896                    result
1897                        .as_ref()
1898                        .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
1899                        .map_err(|err| *err),
1900                );
1901            }
1902            flab::SessionRequest::OpenGpio { resource, endpoint, responder } => {
1903                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1904                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
1905                    continue;
1906                }
1907                let check = {
1908                    let guard = state.inner.lock().unwrap();
1909                    match guard.sessions.session(id) {
1910                        None => Err(flab::OperationError::StaleIdentity),
1911                        Some(session) => match session.policy.resource(resource) {
1912                            None => Err(flab::OperationError::UnknownResource),
1913                            Some(res) => {
1914                                if res.kind != lab_proxy_core::access_policy::ResourceKind::Gpio {
1915                                    Err(flab::OperationError::UnsupportedMethod)
1916                                } else {
1917                                    Ok(())
1918                                }
1919                            }
1920                        },
1921                    }
1922                };
1923                match check {
1924                    Ok(()) => {
1925                        scope.spawn(serve_gpio_endpoint(
1926                            state.clone(),
1927                            id,
1928                            resource,
1929                            endpoint.into_stream(),
1930                        ));
1931                        let _ = responder.send(Ok(()));
1932                    }
1933                    Err(err) => {
1934                        let _ = responder.send(Err(err));
1935                    }
1936                }
1937            }
1938            flab::SessionRequest::OpenI2c { resource, endpoint, responder } => {
1939                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1940                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
1941                    continue;
1942                }
1943                let check = {
1944                    let guard = state.inner.lock().unwrap();
1945                    match guard.sessions.session(id) {
1946                        None => Err(flab::OperationError::StaleIdentity),
1947                        Some(session) => match session.policy.resource(resource) {
1948                            None => Err(flab::OperationError::UnknownResource),
1949                            Some(res) => {
1950                                if res.kind != lab_proxy_core::access_policy::ResourceKind::I2c {
1951                                    Err(flab::OperationError::UnsupportedMethod)
1952                                } else {
1953                                    Ok(())
1954                                }
1955                            }
1956                        },
1957                    }
1958                };
1959                match check {
1960                    Ok(()) => {
1961                        scope.spawn(serve_i2c_endpoint(
1962                            state.clone(),
1963                            id,
1964                            resource,
1965                            endpoint.into_stream(),
1966                        ));
1967                        let _ = responder.send(Ok(()));
1968                    }
1969                    Err(err) => {
1970                        let _ = responder.send(Err(err));
1971                    }
1972                }
1973            }
1974            flab::SessionRequest::OpenSpi { resource, endpoint, responder } => {
1975                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
1976                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
1977                    continue;
1978                }
1979                let check = {
1980                    let guard = state.inner.lock().unwrap();
1981                    match guard.sessions.session(id) {
1982                        None => Err(flab::OperationError::StaleIdentity),
1983                        Some(session) => match session.policy.resource(resource) {
1984                            None => Err(flab::OperationError::UnknownResource),
1985                            Some(res) => {
1986                                if res.kind != lab_proxy_core::access_policy::ResourceKind::Spi {
1987                                    Err(flab::OperationError::UnsupportedMethod)
1988                                } else {
1989                                    Ok(())
1990                                }
1991                            }
1992                        },
1993                    }
1994                };
1995                match check {
1996                    Ok(()) => {
1997                        scope.spawn(serve_spi_endpoint(
1998                            state.clone(),
1999                            id,
2000                            resource,
2001                            endpoint.into_stream(),
2002                        ));
2003                        let _ = responder.send(Ok(()));
2004                    }
2005                    Err(err) => {
2006                        let _ = responder.send(Err(err));
2007                    }
2008                }
2009            }
2010            flab::SessionRequest::WaitForInterrupt {
2011                resource,
2012                after_sequence,
2013                timeout_ns,
2014                responder,
2015            } => {
2016                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2017                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2018                    continue;
2019                }
2020
2021                let (tx, rx) = futures::channel::oneshot::channel();
2022
2023                let wait_init = {
2024                    let mut guard = state.inner.lock().unwrap();
2025                    let ProxyState { sessions, interrupts, audit, .. } = &mut *guard;
2026                    match sessions.session(id) {
2027                        None => Err(flab::OperationError::StaleIdentity),
2028                        Some(session) => match session.policy.check_interrupt(resource) {
2029                            Err(denial) => {
2030                                let record = AuditRecord {
2031                                    session: Some(id),
2032                                    resource: Some(resource),
2033                                    operation: "wait_for_interrupt",
2034                                    offset: None,
2035                                    decision: Decision::Denied(denial),
2036                                    status: OpStatus::Rejected,
2037                                    value: None,
2038                                    timestamp_ns: now_ns(),
2039                                    run_id: None,
2040                                    item_index: None,
2041                                };
2042                                audit.append(record);
2043                                Err(denial_to_fidl(denial))
2044                            }
2045                            Ok(()) => {
2046                                if let Err(denial) = sessions.check_deadline(id, timeout_ns) {
2047                                    let record = AuditRecord {
2048                                        session: Some(id),
2049                                        resource: Some(resource),
2050                                        operation: "wait_for_interrupt",
2051                                        offset: None,
2052                                        decision: Decision::Denied(denial),
2053                                        status: OpStatus::Rejected,
2054                                        value: None,
2055                                        timestamp_ns: now_ns(),
2056                                        run_id: None,
2057                                        item_index: None,
2058                                    };
2059                                    audit.append(record);
2060                                    Err(denial_to_fidl(denial))
2061                                } else if let Err(denial) =
2062                                    sessions.check_access(id, AccessClass::Interrupt, now_ns())
2063                                {
2064                                    let record = AuditRecord {
2065                                        session: Some(id),
2066                                        resource: Some(resource),
2067                                        operation: "wait_for_interrupt",
2068                                        offset: None,
2069                                        decision: Decision::Denied(denial),
2070                                        status: OpStatus::Rejected,
2071                                        value: None,
2072                                        timestamp_ns: now_ns(),
2073                                        run_id: None,
2074                                        item_index: None,
2075                                    };
2076                                    audit.append(record);
2077                                    Err(denial_to_fidl(denial))
2078                                } else {
2079                                    match interrupts.wait_for_interrupt(
2080                                        resource,
2081                                        after_sequence,
2082                                        Box::new(move |event| {
2083                                            let _ = tx.send(event);
2084                                        }),
2085                                    ) {
2086                                        Ok(Some(event)) => Ok(Some(event)),
2087                                        Ok(None) => Ok(None),
2088                                        Err(denial) => {
2089                                            let record = AuditRecord {
2090                                                session: Some(id),
2091                                                resource: Some(resource),
2092                                                operation: "wait_for_interrupt",
2093                                                offset: None,
2094                                                decision: Decision::Denied(denial),
2095                                                status: OpStatus::Rejected,
2096                                                value: None,
2097                                                timestamp_ns: now_ns(),
2098                                                run_id: None,
2099                                                item_index: None,
2100                                            };
2101                                            audit.append(record);
2102                                            Err(denial_to_fidl(denial))
2103                                        }
2104                                    }
2105                                }
2106                            }
2107                        },
2108                    }
2109                };
2110
2111                let event_result = match wait_init {
2112                    Err(err) => Err(err),
2113                    Ok(Some(event)) => Ok(event),
2114                    Ok(None) => {
2115                        if timeout_ns <= 0 {
2116                            Err(flab::OperationError::Timeout)
2117                        } else {
2118                            futures::select! {
2119                                res = rx.fuse() => {
2120                                    match res {
2121                                        Ok(event) => Ok(event),
2122                                        Err(_) => Err(flab::OperationError::NotAccepting),
2123                                    }
2124                                }
2125                                _ = fuchsia_async::Timer::new(zx::MonotonicInstant::after(
2126                                    zx::Duration::from_nanos(timeout_ns),
2127                                )).fuse() => {
2128                                    Err(flab::OperationError::Timeout)
2129                                }
2130                            }
2131                        }
2132                    }
2133                };
2134
2135                let fidl_res = match event_result {
2136                    Ok(event) => {
2137                        let mut guard = state.inner.lock().unwrap();
2138                        let record = AuditRecord {
2139                            session: Some(id),
2140                            resource: Some(resource),
2141                            operation: "wait_for_interrupt",
2142                            offset: None,
2143                            decision: Decision::Allowed,
2144                            status: OpStatus::Ok,
2145                            value: Some(event.count as u32),
2146                            timestamp_ns: event.timestamp_ns,
2147                            run_id: None,
2148                            item_index: None,
2149                        };
2150                        guard.audit.append(record);
2151                        Ok((
2152                            event.resource,
2153                            event.sequence,
2154                            event.count,
2155                            event.timestamp_ns,
2156                            event.coalesced_count,
2157                        ))
2158                    }
2159                    Err(err) => {
2160                        if err == flab::OperationError::Timeout {
2161                            let mut guard = state.inner.lock().unwrap();
2162                            let record = AuditRecord {
2163                                session: Some(id),
2164                                resource: Some(resource),
2165                                operation: "wait_for_interrupt",
2166                                offset: None,
2167                                decision: Decision::Denied(Denial::Timeout),
2168                                status: OpStatus::Rejected,
2169                                value: None,
2170                                timestamp_ns: now_ns(),
2171                                run_id: None,
2172                                item_index: None,
2173                            };
2174                            guard.audit.append(record);
2175                        }
2176                        Err(err)
2177                    }
2178                };
2179
2180                let _ = responder.send(fidl_res);
2181            }
2182            flab::SessionRequest::ClockEnable { resource, responder } => {
2183                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2184                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2185                    continue;
2186                }
2187                let result = {
2188                    let guard = &mut *state.inner.lock().unwrap();
2189                    let ProxyState { sessions, executor, audit, .. } = guard;
2190                    let check = match sessions.session(id) {
2191                        None => Err(flab::OperationError::StaleIdentity),
2192                        Some(session) => {
2193                            session.policy.check_clock_enable(resource).map_err(denial_to_fidl)
2194                        }
2195                    };
2196                    match check {
2197                        Err(flab::OperationError::StaleIdentity) => {
2198                            Err(flab::OperationError::StaleIdentity)
2199                        }
2200                        Err(_) => {
2201                            let session = sessions.session(id).unwrap();
2202                            executor
2203                                .clock_enable(&session.policy, audit, id, resource)
2204                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2205                                .map_err(|error| match error {
2206                                    ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2207                                    ClockOpError::Backend { .. } => {
2208                                        flab::OperationError::BackendFault
2209                                    }
2210                                })
2211                        }
2212                        Ok(_) => {
2213                            let now = now_ns();
2214                            match sessions.check_access(id, AccessClass::Protocol, now) {
2215                                Err(denial) => {
2216                                    let record = AuditRecord {
2217                                        session: Some(id),
2218                                        resource: Some(resource),
2219                                        operation: "clock_enable",
2220                                        offset: None,
2221                                        decision: Decision::Denied(denial),
2222                                        status: OpStatus::Rejected,
2223                                        value: None,
2224                                        timestamp_ns: now,
2225                                        run_id: None,
2226                                        item_index: None,
2227                                    };
2228                                    audit.append(record);
2229                                    Err(denial_to_fidl(denial))
2230                                }
2231                                Ok(()) => {
2232                                    let session = sessions.session(id).unwrap();
2233                                    executor
2234                                        .clock_enable(&session.policy, audit, id, resource)
2235                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2236                                        .map_err(|error| match error {
2237                                            ClockOpError::Denied { denial, .. } => {
2238                                                denial_to_fidl(denial)
2239                                            }
2240                                            ClockOpError::Backend { .. } => {
2241                                                flab::OperationError::BackendFault
2242                                            }
2243                                        })
2244                                }
2245                            }
2246                        }
2247                    }
2248                };
2249                let _ = responder.send(result);
2250            }
2251            flab::SessionRequest::ClockDisable { resource, responder } => {
2252                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2253                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2254                    continue;
2255                }
2256                let result = {
2257                    let guard = &mut *state.inner.lock().unwrap();
2258                    let ProxyState { sessions, executor, audit, .. } = guard;
2259                    let check = match sessions.session(id) {
2260                        None => Err(flab::OperationError::StaleIdentity),
2261                        Some(session) => {
2262                            session.policy.check_clock_disable(resource).map_err(denial_to_fidl)
2263                        }
2264                    };
2265                    match check {
2266                        Err(flab::OperationError::StaleIdentity) => {
2267                            Err(flab::OperationError::StaleIdentity)
2268                        }
2269                        Err(_) => {
2270                            let session = sessions.session(id).unwrap();
2271                            executor
2272                                .clock_disable(&session.policy, audit, id, resource)
2273                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2274                                .map_err(|error| match error {
2275                                    ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2276                                    ClockOpError::Backend { .. } => {
2277                                        flab::OperationError::BackendFault
2278                                    }
2279                                })
2280                        }
2281                        Ok(_) => {
2282                            let now = now_ns();
2283                            match sessions.check_access(id, AccessClass::Protocol, now) {
2284                                Err(denial) => {
2285                                    let record = AuditRecord {
2286                                        session: Some(id),
2287                                        resource: Some(resource),
2288                                        operation: "clock_disable",
2289                                        offset: None,
2290                                        decision: Decision::Denied(denial),
2291                                        status: OpStatus::Rejected,
2292                                        value: None,
2293                                        timestamp_ns: now,
2294                                        run_id: None,
2295                                        item_index: None,
2296                                    };
2297                                    audit.append(record);
2298                                    Err(denial_to_fidl(denial))
2299                                }
2300                                Ok(()) => {
2301                                    let session = sessions.session(id).unwrap();
2302                                    executor
2303                                        .clock_disable(&session.policy, audit, id, resource)
2304                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2305                                        .map_err(|error| match error {
2306                                            ClockOpError::Denied { denial, .. } => {
2307                                                denial_to_fidl(denial)
2308                                            }
2309                                            ClockOpError::Backend { .. } => {
2310                                                flab::OperationError::BackendFault
2311                                            }
2312                                        })
2313                                }
2314                            }
2315                        }
2316                    }
2317                };
2318                let _ = responder.send(result);
2319            }
2320            flab::SessionRequest::ClockIsEnabled { resource, responder } => {
2321                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2322                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2323                    continue;
2324                }
2325                let result = {
2326                    let guard = &mut *state.inner.lock().unwrap();
2327                    let ProxyState { sessions, executor, audit, .. } = guard;
2328                    let check = match sessions.session(id) {
2329                        None => Err(flab::OperationError::StaleIdentity),
2330                        Some(session) => {
2331                            session.policy.check_clock_is_enabled(resource).map_err(denial_to_fidl)
2332                        }
2333                    };
2334                    match check {
2335                        Err(flab::OperationError::StaleIdentity) => {
2336                            Err(flab::OperationError::StaleIdentity)
2337                        }
2338                        Err(_) => {
2339                            let session = sessions.session(id).unwrap();
2340                            executor
2341                                .clock_is_enabled(&session.policy, audit, id, resource)
2342                                .map(|outcome| {
2343                                    (outcome.enabled, outcome.audit_seq, outcome.timestamp_ns)
2344                                })
2345                                .map_err(|error| match error {
2346                                    ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2347                                    ClockOpError::Backend { .. } => {
2348                                        flab::OperationError::BackendFault
2349                                    }
2350                                })
2351                        }
2352                        Ok(_) => {
2353                            let now = now_ns();
2354                            match sessions.check_access(id, AccessClass::Protocol, now) {
2355                                Err(denial) => {
2356                                    let record = AuditRecord {
2357                                        session: Some(id),
2358                                        resource: Some(resource),
2359                                        operation: "clock_is_enabled",
2360                                        offset: None,
2361                                        decision: Decision::Denied(denial),
2362                                        status: OpStatus::Rejected,
2363                                        value: None,
2364                                        timestamp_ns: now,
2365                                        run_id: None,
2366                                        item_index: None,
2367                                    };
2368                                    audit.append(record);
2369                                    Err(denial_to_fidl(denial))
2370                                }
2371                                Ok(()) => {
2372                                    let session = sessions.session(id).unwrap();
2373                                    executor
2374                                        .clock_is_enabled(&session.policy, audit, id, resource)
2375                                        .map(|outcome| {
2376                                            (
2377                                                outcome.enabled,
2378                                                outcome.audit_seq,
2379                                                outcome.timestamp_ns,
2380                                            )
2381                                        })
2382                                        .map_err(|error| match error {
2383                                            ClockOpError::Denied { denial, .. } => {
2384                                                denial_to_fidl(denial)
2385                                            }
2386                                            ClockOpError::Backend { .. } => {
2387                                                flab::OperationError::BackendFault
2388                                            }
2389                                        })
2390                                }
2391                            }
2392                        }
2393                    }
2394                };
2395                let _ = responder.send(result);
2396            }
2397            flab::SessionRequest::ClockSetRate { resource, hz, responder } => {
2398                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2399                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2400                    continue;
2401                }
2402                let result = {
2403                    let guard = &mut *state.inner.lock().unwrap();
2404                    let ProxyState { sessions, executor, audit, .. } = guard;
2405                    let check = match sessions.session(id) {
2406                        None => Err(flab::OperationError::StaleIdentity),
2407                        Some(session) => {
2408                            session.policy.check_clock_set_rate(resource).map_err(denial_to_fidl)
2409                        }
2410                    };
2411                    match check {
2412                        Err(flab::OperationError::StaleIdentity) => {
2413                            Err(flab::OperationError::StaleIdentity)
2414                        }
2415                        Err(_) => {
2416                            let session = sessions.session(id).unwrap();
2417                            executor
2418                                .clock_set_rate(&session.policy, audit, id, resource, hz)
2419                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2420                                .map_err(|error| match error {
2421                                    ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2422                                    ClockOpError::Backend { .. } => {
2423                                        flab::OperationError::BackendFault
2424                                    }
2425                                })
2426                        }
2427                        Ok(_) => {
2428                            let now = now_ns();
2429                            match sessions.check_access(id, AccessClass::Protocol, now) {
2430                                Err(denial) => {
2431                                    let record = AuditRecord {
2432                                        session: Some(id),
2433                                        resource: Some(resource),
2434                                        operation: "clock_set_rate",
2435                                        offset: None,
2436                                        decision: Decision::Denied(denial),
2437                                        status: OpStatus::Rejected,
2438                                        value: None,
2439                                        timestamp_ns: now,
2440                                        run_id: None,
2441                                        item_index: None,
2442                                    };
2443                                    audit.append(record);
2444                                    Err(denial_to_fidl(denial))
2445                                }
2446                                Ok(()) => {
2447                                    let session = sessions.session(id).unwrap();
2448                                    executor
2449                                        .clock_set_rate(&session.policy, audit, id, resource, hz)
2450                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2451                                        .map_err(|error| match error {
2452                                            ClockOpError::Denied { denial, .. } => {
2453                                                denial_to_fidl(denial)
2454                                            }
2455                                            ClockOpError::Backend { .. } => {
2456                                                flab::OperationError::BackendFault
2457                                            }
2458                                        })
2459                                }
2460                            }
2461                        }
2462                    }
2463                };
2464                let _ = responder.send(result);
2465            }
2466            flab::SessionRequest::ClockQueryRate { resource, hz_in, responder } => {
2467                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2468                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2469                    continue;
2470                }
2471                let result = {
2472                    let guard = &mut *state.inner.lock().unwrap();
2473                    let ProxyState { sessions, executor, audit, .. } = guard;
2474                    let check = match sessions.session(id) {
2475                        None => Err(flab::OperationError::StaleIdentity),
2476                        Some(session) => {
2477                            session.policy.check_clock_query_rate(resource).map_err(denial_to_fidl)
2478                        }
2479                    };
2480                    match check {
2481                        Err(flab::OperationError::StaleIdentity) => {
2482                            Err(flab::OperationError::StaleIdentity)
2483                        }
2484                        Err(_) => {
2485                            let session = sessions.session(id).unwrap();
2486                            executor
2487                                .clock_query_rate(&session.policy, audit, id, resource, hz_in)
2488                                .map(|outcome| {
2489                                    (outcome.hz_out, outcome.audit_seq, outcome.timestamp_ns)
2490                                })
2491                                .map_err(|error| match error {
2492                                    ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2493                                    ClockOpError::Backend { .. } => {
2494                                        flab::OperationError::BackendFault
2495                                    }
2496                                })
2497                        }
2498                        Ok(_) => {
2499                            let now = now_ns();
2500                            match sessions.check_access(id, AccessClass::Protocol, now) {
2501                                Err(denial) => {
2502                                    let record = AuditRecord {
2503                                        session: Some(id),
2504                                        resource: Some(resource),
2505                                        operation: "clock_query_rate",
2506                                        offset: None,
2507                                        decision: Decision::Denied(denial),
2508                                        status: OpStatus::Rejected,
2509                                        value: None,
2510                                        timestamp_ns: now,
2511                                        run_id: None,
2512                                        item_index: None,
2513                                    };
2514                                    audit.append(record);
2515                                    Err(denial_to_fidl(denial))
2516                                }
2517                                Ok(()) => {
2518                                    let session = sessions.session(id).unwrap();
2519                                    executor
2520                                        .clock_query_rate(
2521                                            &session.policy,
2522                                            audit,
2523                                            id,
2524                                            resource,
2525                                            hz_in,
2526                                        )
2527                                        .map(|outcome| {
2528                                            (
2529                                                outcome.hz_out,
2530                                                outcome.audit_seq,
2531                                                outcome.timestamp_ns,
2532                                            )
2533                                        })
2534                                        .map_err(|error| match error {
2535                                            ClockOpError::Denied { denial, .. } => {
2536                                                denial_to_fidl(denial)
2537                                            }
2538                                            ClockOpError::Backend { .. } => {
2539                                                flab::OperationError::BackendFault
2540                                            }
2541                                        })
2542                                }
2543                            }
2544                        }
2545                    }
2546                };
2547                let _ = responder.send(result);
2548            }
2549            flab::SessionRequest::ClockGetRate { resource, responder } => {
2550                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2551                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2552                    continue;
2553                }
2554                let result = {
2555                    let guard = &mut *state.inner.lock().unwrap();
2556                    let ProxyState { sessions, executor, audit, .. } = guard;
2557                    let check = match sessions.session(id) {
2558                        None => Err(flab::OperationError::StaleIdentity),
2559                        Some(session) => {
2560                            session.policy.check_clock_get_rate(resource).map_err(denial_to_fidl)
2561                        }
2562                    };
2563                    match check {
2564                        Err(flab::OperationError::StaleIdentity) => {
2565                            Err(flab::OperationError::StaleIdentity)
2566                        }
2567                        Err(_) => {
2568                            let session = sessions.session(id).unwrap();
2569                            executor
2570                                .clock_get_rate(&session.policy, audit, id, resource)
2571                                .map(|outcome| {
2572                                    (outcome.hz, outcome.audit_seq, outcome.timestamp_ns)
2573                                })
2574                                .map_err(|error| match error {
2575                                    ClockOpError::Denied { denial, .. } => denial_to_fidl(denial),
2576                                    ClockOpError::Backend { .. } => {
2577                                        flab::OperationError::BackendFault
2578                                    }
2579                                })
2580                        }
2581                        Ok(_) => {
2582                            let now = now_ns();
2583                            match sessions.check_access(id, AccessClass::Protocol, now) {
2584                                Err(denial) => {
2585                                    let record = AuditRecord {
2586                                        session: Some(id),
2587                                        resource: Some(resource),
2588                                        operation: "clock_get_rate",
2589                                        offset: None,
2590                                        decision: Decision::Denied(denial),
2591                                        status: OpStatus::Rejected,
2592                                        value: None,
2593                                        timestamp_ns: now,
2594                                        run_id: None,
2595                                        item_index: None,
2596                                    };
2597                                    audit.append(record);
2598                                    Err(denial_to_fidl(denial))
2599                                }
2600                                Ok(()) => {
2601                                    let session = sessions.session(id).unwrap();
2602                                    executor
2603                                        .clock_get_rate(&session.policy, audit, id, resource)
2604                                        .map(|outcome| {
2605                                            (outcome.hz, outcome.audit_seq, outcome.timestamp_ns)
2606                                        })
2607                                        .map_err(|error| match error {
2608                                            ClockOpError::Denied { denial, .. } => {
2609                                                denial_to_fidl(denial)
2610                                            }
2611                                            ClockOpError::Backend { .. } => {
2612                                                flab::OperationError::BackendFault
2613                                            }
2614                                        })
2615                                }
2616                            }
2617                        }
2618                    }
2619                };
2620                let _ = responder.send(result);
2621            }
2622            flab::SessionRequest::ResetAssert { resource, responder } => {
2623                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2624                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2625                    continue;
2626                }
2627                let result = {
2628                    let guard = &mut *state.inner.lock().unwrap();
2629                    let ProxyState { sessions, executor, audit, .. } = guard;
2630                    let check = match sessions.session(id) {
2631                        None => Err(flab::OperationError::StaleIdentity),
2632                        Some(session) => {
2633                            session.policy.check_reset_assert(resource).map_err(denial_to_fidl)
2634                        }
2635                    };
2636                    match check {
2637                        Err(flab::OperationError::StaleIdentity) => {
2638                            Err(flab::OperationError::StaleIdentity)
2639                        }
2640                        Err(_) => {
2641                            let session = sessions.session(id).unwrap();
2642                            executor
2643                                .reset_assert(&session.policy, audit, id, resource)
2644                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2645                                .map_err(|error| match error {
2646                                    ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2647                                    ResetOpError::Backend { .. } => {
2648                                        flab::OperationError::BackendFault
2649                                    }
2650                                })
2651                        }
2652                        Ok(_) => {
2653                            let now = now_ns();
2654                            match sessions.check_access(id, AccessClass::Protocol, now) {
2655                                Err(denial) => {
2656                                    let record = AuditRecord {
2657                                        session: Some(id),
2658                                        resource: Some(resource),
2659                                        operation: "reset_assert",
2660                                        offset: None,
2661                                        decision: Decision::Denied(denial),
2662                                        status: OpStatus::Rejected,
2663                                        value: None,
2664                                        timestamp_ns: now,
2665                                        run_id: None,
2666                                        item_index: None,
2667                                    };
2668                                    audit.append(record);
2669                                    Err(denial_to_fidl(denial))
2670                                }
2671                                Ok(()) => {
2672                                    let session = sessions.session(id).unwrap();
2673                                    executor
2674                                        .reset_assert(&session.policy, audit, id, resource)
2675                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2676                                        .map_err(|error| match error {
2677                                            ResetOpError::Denied { denial, .. } => {
2678                                                denial_to_fidl(denial)
2679                                            }
2680                                            ResetOpError::Backend { .. } => {
2681                                                flab::OperationError::BackendFault
2682                                            }
2683                                        })
2684                                }
2685                            }
2686                        }
2687                    }
2688                };
2689                let _ = responder.send(result);
2690            }
2691            flab::SessionRequest::ResetDeassert { resource, responder } => {
2692                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2693                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2694                    continue;
2695                }
2696                let result = {
2697                    let guard = &mut *state.inner.lock().unwrap();
2698                    let ProxyState { sessions, executor, audit, .. } = guard;
2699                    let check = match sessions.session(id) {
2700                        None => Err(flab::OperationError::StaleIdentity),
2701                        Some(session) => {
2702                            session.policy.check_reset_deassert(resource).map_err(denial_to_fidl)
2703                        }
2704                    };
2705                    match check {
2706                        Err(flab::OperationError::StaleIdentity) => {
2707                            Err(flab::OperationError::StaleIdentity)
2708                        }
2709                        Err(_) => {
2710                            let session = sessions.session(id).unwrap();
2711                            executor
2712                                .reset_deassert(&session.policy, audit, id, resource)
2713                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2714                                .map_err(|error| match error {
2715                                    ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2716                                    ResetOpError::Backend { .. } => {
2717                                        flab::OperationError::BackendFault
2718                                    }
2719                                })
2720                        }
2721                        Ok(_) => {
2722                            let now = now_ns();
2723                            match sessions.check_access(id, AccessClass::Protocol, now) {
2724                                Err(denial) => {
2725                                    let record = AuditRecord {
2726                                        session: Some(id),
2727                                        resource: Some(resource),
2728                                        operation: "reset_deassert",
2729                                        offset: None,
2730                                        decision: Decision::Denied(denial),
2731                                        status: OpStatus::Rejected,
2732                                        value: None,
2733                                        timestamp_ns: now,
2734                                        run_id: None,
2735                                        item_index: None,
2736                                    };
2737                                    audit.append(record);
2738                                    Err(denial_to_fidl(denial))
2739                                }
2740                                Ok(()) => {
2741                                    let session = sessions.session(id).unwrap();
2742                                    executor
2743                                        .reset_deassert(&session.policy, audit, id, resource)
2744                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2745                                        .map_err(|error| match error {
2746                                            ResetOpError::Denied { denial, .. } => {
2747                                                denial_to_fidl(denial)
2748                                            }
2749                                            ResetOpError::Backend { .. } => {
2750                                                flab::OperationError::BackendFault
2751                                            }
2752                                        })
2753                                }
2754                            }
2755                        }
2756                    }
2757                };
2758                let _ = responder.send(result);
2759            }
2760            flab::SessionRequest::ResetToggle { resource, responder } => {
2761                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2762                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2763                    continue;
2764                }
2765                let result = {
2766                    let guard = &mut *state.inner.lock().unwrap();
2767                    let ProxyState { sessions, executor, audit, .. } = guard;
2768                    let check = match sessions.session(id) {
2769                        None => Err(flab::OperationError::StaleIdentity),
2770                        Some(session) => {
2771                            session.policy.check_reset_toggle(resource).map_err(denial_to_fidl)
2772                        }
2773                    };
2774                    match check {
2775                        Err(flab::OperationError::StaleIdentity) => {
2776                            Err(flab::OperationError::StaleIdentity)
2777                        }
2778                        Err(_) => {
2779                            let session = sessions.session(id).unwrap();
2780                            executor
2781                                .reset_toggle(&session.policy, audit, id, resource)
2782                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2783                                .map_err(|error| match error {
2784                                    ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2785                                    ResetOpError::Backend { .. } => {
2786                                        flab::OperationError::BackendFault
2787                                    }
2788                                })
2789                        }
2790                        Ok(_) => {
2791                            let now = now_ns();
2792                            match sessions.check_access(id, AccessClass::Protocol, now) {
2793                                Err(denial) => {
2794                                    let record = AuditRecord {
2795                                        session: Some(id),
2796                                        resource: Some(resource),
2797                                        operation: "reset_toggle",
2798                                        offset: None,
2799                                        decision: Decision::Denied(denial),
2800                                        status: OpStatus::Rejected,
2801                                        value: None,
2802                                        timestamp_ns: now,
2803                                        run_id: None,
2804                                        item_index: None,
2805                                    };
2806                                    audit.append(record);
2807                                    Err(denial_to_fidl(denial))
2808                                }
2809                                Ok(()) => {
2810                                    let session = sessions.session(id).unwrap();
2811                                    executor
2812                                        .reset_toggle(&session.policy, audit, id, resource)
2813                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
2814                                        .map_err(|error| match error {
2815                                            ResetOpError::Denied { denial, .. } => {
2816                                                denial_to_fidl(denial)
2817                                            }
2818                                            ResetOpError::Backend { .. } => {
2819                                                flab::OperationError::BackendFault
2820                                            }
2821                                        })
2822                                }
2823                            }
2824                        }
2825                    }
2826                };
2827                let _ = responder.send(result);
2828            }
2829            flab::SessionRequest::ResetStatus { resource, responder } => {
2830                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2831                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2832                    continue;
2833                }
2834                let result = {
2835                    let guard = &mut *state.inner.lock().unwrap();
2836                    let ProxyState { sessions, executor, audit, .. } = guard;
2837                    let check = match sessions.session(id) {
2838                        None => Err(flab::OperationError::StaleIdentity),
2839                        Some(session) => {
2840                            session.policy.check_reset_status(resource).map_err(denial_to_fidl)
2841                        }
2842                    };
2843                    match check {
2844                        Err(flab::OperationError::StaleIdentity) => {
2845                            Err(flab::OperationError::StaleIdentity)
2846                        }
2847                        Err(_) => {
2848                            let session = sessions.session(id).unwrap();
2849                            executor
2850                                .reset_status(&session.policy, audit, id, resource)
2851                                .map(|outcome| {
2852                                    (outcome.asserted, outcome.audit_seq, outcome.timestamp_ns)
2853                                })
2854                                .map_err(|error| match error {
2855                                    ResetOpError::Denied { denial, .. } => denial_to_fidl(denial),
2856                                    ResetOpError::Backend { .. } => {
2857                                        flab::OperationError::BackendFault
2858                                    }
2859                                })
2860                        }
2861                        Ok(_) => {
2862                            let now = now_ns();
2863                            match sessions.check_access(id, AccessClass::Protocol, now) {
2864                                Err(denial) => {
2865                                    let record = AuditRecord {
2866                                        session: Some(id),
2867                                        resource: Some(resource),
2868                                        operation: "reset_status",
2869                                        offset: None,
2870                                        decision: Decision::Denied(denial),
2871                                        status: OpStatus::Rejected,
2872                                        value: None,
2873                                        timestamp_ns: now,
2874                                        run_id: None,
2875                                        item_index: None,
2876                                    };
2877                                    audit.append(record);
2878                                    Err(denial_to_fidl(denial))
2879                                }
2880                                Ok(()) => {
2881                                    let session = sessions.session(id).unwrap();
2882                                    executor
2883                                        .reset_status(&session.policy, audit, id, resource)
2884                                        .map(|outcome| {
2885                                            (
2886                                                outcome.asserted,
2887                                                outcome.audit_seq,
2888                                                outcome.timestamp_ns,
2889                                            )
2890                                        })
2891                                        .map_err(|error| match error {
2892                                            ResetOpError::Denied { denial, .. } => {
2893                                                denial_to_fidl(denial)
2894                                            }
2895                                            ResetOpError::Backend { .. } => {
2896                                                flab::OperationError::BackendFault
2897                                            }
2898                                        })
2899                                }
2900                            }
2901                        }
2902                    }
2903                };
2904                let _ = responder.send(result);
2905            }
2906            flab::SessionRequest::SerialRead { resource, responder } => {
2907                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2908                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2909                    continue;
2910                }
2911                let result = {
2912                    let guard = &mut *state.inner.lock().unwrap();
2913                    let ProxyState { sessions, executor, audit, .. } = guard;
2914                    let check = match sessions.session(id) {
2915                        None => Err(flab::OperationError::StaleIdentity),
2916                        Some(session) => {
2917                            session.policy.check_serial_read(resource).map_err(denial_to_fidl)
2918                        }
2919                    };
2920                    match check {
2921                        Err(flab::OperationError::StaleIdentity) => {
2922                            Err(flab::OperationError::StaleIdentity)
2923                        }
2924                        Err(_) => {
2925                            let session = sessions.session(id).unwrap();
2926                            executor
2927                                .serial_read(&session.policy, audit, id, resource)
2928                                .map(|outcome| {
2929                                    (outcome.data, outcome.audit_seq, outcome.timestamp_ns)
2930                                })
2931                                .map_err(|error| match error {
2932                                    SerialOpError::Denied { denial, .. } => denial_to_fidl(denial),
2933                                    SerialOpError::Backend { .. } => {
2934                                        flab::OperationError::BackendFault
2935                                    }
2936                                })
2937                        }
2938                        Ok(_) => {
2939                            let now = now_ns();
2940                            match sessions.check_access(id, AccessClass::Protocol, now) {
2941                                Err(denial) => {
2942                                    let record = AuditRecord {
2943                                        session: Some(id),
2944                                        resource: Some(resource),
2945                                        operation: "serial_read",
2946                                        offset: None,
2947                                        decision: Decision::Denied(denial),
2948                                        status: OpStatus::Rejected,
2949                                        value: None,
2950                                        timestamp_ns: now,
2951                                        run_id: None,
2952                                        item_index: None,
2953                                    };
2954                                    audit.append(record);
2955                                    Err(denial_to_fidl(denial))
2956                                }
2957                                Ok(()) => {
2958                                    let session = sessions.session(id).unwrap();
2959                                    executor
2960                                        .serial_read(&session.policy, audit, id, resource)
2961                                        .map(|outcome| {
2962                                            (outcome.data, outcome.audit_seq, outcome.timestamp_ns)
2963                                        })
2964                                        .map_err(|error| match error {
2965                                            SerialOpError::Denied { denial, .. } => {
2966                                                denial_to_fidl(denial)
2967                                            }
2968                                            SerialOpError::Backend { .. } => {
2969                                                flab::OperationError::BackendFault
2970                                            }
2971                                        })
2972                                }
2973                            }
2974                        }
2975                    }
2976                };
2977                let _ = responder.send(
2978                    result
2979                        .as_ref()
2980                        .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
2981                        .map_err(|err| *err),
2982                );
2983            }
2984            flab::SessionRequest::SerialWrite { resource, data, responder } => {
2985                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
2986                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
2987                    continue;
2988                }
2989                let result = {
2990                    let guard = &mut *state.inner.lock().unwrap();
2991                    let ProxyState { sessions, executor, audit, .. } = guard;
2992                    let check = match sessions.session(id) {
2993                        None => Err(flab::OperationError::StaleIdentity),
2994                        Some(session) => session
2995                            .policy
2996                            .check_serial_write(resource, data.len())
2997                            .map_err(denial_to_fidl),
2998                    };
2999                    match check {
3000                        Err(flab::OperationError::StaleIdentity) => {
3001                            Err(flab::OperationError::StaleIdentity)
3002                        }
3003                        Err(_) => {
3004                            let session = sessions.session(id).unwrap();
3005                            executor
3006                                .serial_write(&session.policy, audit, id, resource, &data)
3007                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3008                                .map_err(|error| match error {
3009                                    SerialOpError::Denied { denial, .. } => denial_to_fidl(denial),
3010                                    SerialOpError::Backend { .. } => {
3011                                        flab::OperationError::BackendFault
3012                                    }
3013                                })
3014                        }
3015                        Ok(_) => {
3016                            let now = now_ns();
3017                            match sessions.check_access(id, AccessClass::Protocol, now) {
3018                                Err(denial) => {
3019                                    let record = AuditRecord {
3020                                        session: Some(id),
3021                                        resource: Some(resource),
3022                                        operation: "serial_write",
3023                                        offset: None,
3024                                        decision: Decision::Denied(denial),
3025                                        status: OpStatus::Rejected,
3026                                        value: None,
3027                                        timestamp_ns: now,
3028                                        run_id: None,
3029                                        item_index: None,
3030                                    };
3031                                    audit.append(record);
3032                                    Err(denial_to_fidl(denial))
3033                                }
3034                                Ok(()) => {
3035                                    let session = sessions.session(id).unwrap();
3036                                    executor
3037                                        .serial_write(&session.policy, audit, id, resource, &data)
3038                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3039                                        .map_err(|error| match error {
3040                                            SerialOpError::Denied { denial, .. } => {
3041                                                denial_to_fidl(denial)
3042                                            }
3043                                            SerialOpError::Backend { .. } => {
3044                                                flab::OperationError::BackendFault
3045                                            }
3046                                        })
3047                                }
3048                            }
3049                        }
3050                    }
3051                };
3052                let _ = responder.send(result);
3053            }
3054            flab::SessionRequest::_UnknownMethod { .. } => {}
3055        }
3056    }
3057
3058    // Channel closed: close the session, release the mutation lease, and
3059    // audit the closure.
3060    let mut state = state.inner.lock().unwrap();
3061    state.interrupts.cancel_waiters();
3062    let was_mutating =
3063        state.sessions.session(id).map(|s| s.mode == SessionMode::Mutating).unwrap_or(false);
3064    if state.sessions.close_session(id) {
3065        if was_mutating {
3066            let mut q_record = AuditRecord::lifecycle("quiesce_released", now_ns());
3067            q_record.session = Some(id);
3068            state.audit.append(q_record);
3069        }
3070        let mut record = AuditRecord::lifecycle("session_closed", now_ns());
3071        record.session = Some(id);
3072        state.audit.append(record);
3073    }
3074}
3075
3076async fn serve_gpio_endpoint(
3077    state: SharedState,
3078    session_id: u64,
3079    resource: u32,
3080    mut stream: flab::GpioEndpointRequestStream,
3081) {
3082    while let Ok(Some(request)) = stream.try_next().await {
3083        match request {
3084            flab::GpioEndpointRequest::Read { responder } => {
3085                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3086                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
3087                    continue;
3088                }
3089                let result = {
3090                    let guard = &mut *state.inner.lock().unwrap();
3091                    let ProxyState { sessions, executor, audit, .. } = guard;
3092                    let check = match sessions.session(session_id) {
3093                        None => Err(flab::OperationError::StaleIdentity),
3094                        Some(session) => {
3095                            session.policy.check_gpio_read(resource).map_err(denial_to_fidl)
3096                        }
3097                    };
3098                    match check {
3099                        Err(flab::OperationError::StaleIdentity) => {
3100                            Err(flab::OperationError::StaleIdentity)
3101                        }
3102                        Err(_) => {
3103                            let session = sessions.session(session_id).unwrap();
3104                            executor
3105                                .gpio_read(&session.policy, audit, session_id, resource)
3106                                .map(|outcome| {
3107                                    (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
3108                                })
3109                                .map_err(|error| match error {
3110                                    GpioReadError::Denied { denial, .. } => denial_to_fidl(denial),
3111                                    GpioReadError::Backend { .. } => {
3112                                        flab::OperationError::BackendFault
3113                                    }
3114                                })
3115                        }
3116                        Ok(_) => {
3117                            let now = now_ns();
3118                            match sessions.check_access(session_id, AccessClass::Protocol, now) {
3119                                Err(denial) => {
3120                                    let record = AuditRecord {
3121                                        session: Some(session_id),
3122                                        resource: Some(resource),
3123                                        operation: "gpio_read",
3124                                        offset: None,
3125                                        decision: Decision::Denied(denial),
3126                                        status: OpStatus::Rejected,
3127                                        value: None,
3128                                        timestamp_ns: now,
3129                                        run_id: None,
3130                                        item_index: None,
3131                                    };
3132                                    audit.append(record);
3133                                    Err(denial_to_fidl(denial))
3134                                }
3135                                Ok(()) => {
3136                                    let session = sessions.session(session_id).unwrap();
3137                                    executor
3138                                        .gpio_read(&session.policy, audit, session_id, resource)
3139                                        .map(|outcome| {
3140                                            (outcome.value, outcome.audit_seq, outcome.timestamp_ns)
3141                                        })
3142                                        .map_err(|error| match error {
3143                                            GpioReadError::Denied { denial, .. } => {
3144                                                denial_to_fidl(denial)
3145                                            }
3146                                            GpioReadError::Backend { .. } => {
3147                                                flab::OperationError::BackendFault
3148                                            }
3149                                        })
3150                                }
3151                            }
3152                        }
3153                    }
3154                };
3155                let _ = responder.send(result);
3156            }
3157            flab::GpioEndpointRequest::Write { value, responder } => {
3158                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3159                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
3160                    continue;
3161                }
3162                let result = {
3163                    let guard = &mut *state.inner.lock().unwrap();
3164                    let ProxyState { sessions, executor, audit, .. } = guard;
3165                    let check = match sessions.session(session_id) {
3166                        None => Err(flab::OperationError::StaleIdentity),
3167                        Some(session) => {
3168                            session.policy.check_gpio_write(resource).map_err(denial_to_fidl)
3169                        }
3170                    };
3171                    match check {
3172                        Err(flab::OperationError::StaleIdentity) => {
3173                            Err(flab::OperationError::StaleIdentity)
3174                        }
3175                        Err(_) => {
3176                            let session = sessions.session(session_id).unwrap();
3177                            executor
3178                                .gpio_write(&session.policy, audit, session_id, resource, value)
3179                                .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3180                                .map_err(|error| match error {
3181                                    GpioWriteError::Denied { denial, .. } => denial_to_fidl(denial),
3182                                    GpioWriteError::Backend { .. } => {
3183                                        flab::OperationError::BackendFault
3184                                    }
3185                                })
3186                        }
3187                        Ok(_) => {
3188                            let now = now_ns();
3189                            match sessions.check_access(session_id, AccessClass::Protocol, now) {
3190                                Err(denial) => {
3191                                    let record = AuditRecord {
3192                                        session: Some(session_id),
3193                                        resource: Some(resource),
3194                                        operation: "gpio_write",
3195                                        offset: None,
3196                                        decision: Decision::Denied(denial),
3197                                        status: OpStatus::Rejected,
3198                                        value: None,
3199                                        timestamp_ns: now,
3200                                        run_id: None,
3201                                        item_index: None,
3202                                    };
3203                                    audit.append(record);
3204                                    Err(denial_to_fidl(denial))
3205                                }
3206                                Ok(()) => {
3207                                    let session = sessions.session(session_id).unwrap();
3208                                    executor
3209                                        .gpio_write(
3210                                            &session.policy,
3211                                            audit,
3212                                            session_id,
3213                                            resource,
3214                                            value,
3215                                        )
3216                                        .map(|outcome| (outcome.audit_seq, outcome.timestamp_ns))
3217                                        .map_err(|error| match error {
3218                                            GpioWriteError::Denied { denial, .. } => {
3219                                                denial_to_fidl(denial)
3220                                            }
3221                                            GpioWriteError::Backend { .. } => {
3222                                                flab::OperationError::BackendFault
3223                                            }
3224                                        })
3225                                }
3226                            }
3227                        }
3228                    }
3229                };
3230                let _ = responder.send(result);
3231            }
3232            flab::GpioEndpointRequest::_UnknownMethod { .. } => {}
3233        }
3234    }
3235}
3236
3237async fn serve_i2c_endpoint(
3238    state: SharedState,
3239    session_id: u64,
3240    resource: u32,
3241    mut stream: flab::I2cEndpointRequestStream,
3242) {
3243    while let Ok(Some(request)) = stream.try_next().await {
3244        match request {
3245            flab::I2cEndpointRequest::Transfer { write_data, read_length, responder } => {
3246                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3247                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
3248                    continue;
3249                }
3250                let result = {
3251                    let guard = &mut *state.inner.lock().unwrap();
3252                    let ProxyState { sessions, executor, audit, .. } = guard;
3253                    let check = match sessions.session(session_id) {
3254                        None => Err(flab::OperationError::StaleIdentity),
3255                        Some(session) => session
3256                            .policy
3257                            .check_i2c_transfer(resource, write_data.len(), read_length as usize)
3258                            .map_err(denial_to_fidl),
3259                    };
3260                    match check {
3261                        Err(flab::OperationError::StaleIdentity) => {
3262                            Err(flab::OperationError::StaleIdentity)
3263                        }
3264                        Err(_) => {
3265                            let session = sessions.session(session_id).unwrap();
3266                            executor
3267                                .i2c_transfer(
3268                                    &session.policy,
3269                                    audit,
3270                                    session_id,
3271                                    resource,
3272                                    &write_data,
3273                                    read_length,
3274                                )
3275                                .map(|outcome| {
3276                                    (outcome.read_data, outcome.audit_seq, outcome.timestamp_ns)
3277                                })
3278                                .map_err(|error| match error {
3279                                    I2cTransferError::Denied { denial, .. } => {
3280                                        denial_to_fidl(denial)
3281                                    }
3282                                    I2cTransferError::Backend { .. } => {
3283                                        flab::OperationError::BackendFault
3284                                    }
3285                                })
3286                        }
3287                        Ok(_) => {
3288                            let now = now_ns();
3289                            match sessions.check_access(session_id, AccessClass::Protocol, now) {
3290                                Err(denial) => {
3291                                    let record = AuditRecord {
3292                                        session: Some(session_id),
3293                                        resource: Some(resource),
3294                                        operation: "i2c_transfer",
3295                                        offset: None,
3296                                        decision: Decision::Denied(denial),
3297                                        status: OpStatus::Rejected,
3298                                        value: None,
3299                                        timestamp_ns: now,
3300                                        run_id: None,
3301                                        item_index: None,
3302                                    };
3303                                    audit.append(record);
3304                                    Err(denial_to_fidl(denial))
3305                                }
3306                                Ok(()) => {
3307                                    let session = sessions.session(session_id).unwrap();
3308                                    executor
3309                                        .i2c_transfer(
3310                                            &session.policy,
3311                                            audit,
3312                                            session_id,
3313                                            resource,
3314                                            &write_data,
3315                                            read_length,
3316                                        )
3317                                        .map(|outcome| {
3318                                            (
3319                                                outcome.read_data,
3320                                                outcome.audit_seq,
3321                                                outcome.timestamp_ns,
3322                                            )
3323                                        })
3324                                        .map_err(|error| match error {
3325                                            I2cTransferError::Denied { denial, .. } => {
3326                                                denial_to_fidl(denial)
3327                                            }
3328                                            I2cTransferError::Backend { .. } => {
3329                                                flab::OperationError::BackendFault
3330                                            }
3331                                        })
3332                                }
3333                            }
3334                        }
3335                    }
3336                };
3337                let _ = responder.send(
3338                    result
3339                        .as_ref()
3340                        .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
3341                        .map_err(|err| *err),
3342                );
3343            }
3344            flab::I2cEndpointRequest::_UnknownMethod { .. } => {}
3345        }
3346    }
3347}
3348
3349async fn serve_spi_endpoint(
3350    state: SharedState,
3351    session_id: u64,
3352    resource: u32,
3353    mut stream: flab::SpiEndpointRequestStream,
3354) {
3355    while let Ok(Some(request)) = stream.try_next().await {
3356        match request {
3357            flab::SpiEndpointRequest::Transmit { tx_data, responder } => {
3358                if state.abort_token.load(std::sync::atomic::Ordering::SeqCst) {
3359                    let _ = responder.send(Err(flab::OperationError::NotAccepting));
3360                    continue;
3361                }
3362                let result = {
3363                    let guard = &mut *state.inner.lock().unwrap();
3364                    let ProxyState { sessions, executor, audit, .. } = guard;
3365                    let check = match sessions.session(session_id) {
3366                        None => Err(flab::OperationError::StaleIdentity),
3367                        Some(session) => session
3368                            .policy
3369                            .check_spi_transmit(resource, tx_data.len())
3370                            .map_err(denial_to_fidl),
3371                    };
3372                    match check {
3373                        Err(flab::OperationError::StaleIdentity) => {
3374                            Err(flab::OperationError::StaleIdentity)
3375                        }
3376                        Err(_) => {
3377                            let session = sessions.session(session_id).unwrap();
3378                            executor
3379                                .spi_transmit(
3380                                    &session.policy,
3381                                    audit,
3382                                    session_id,
3383                                    resource,
3384                                    &tx_data,
3385                                )
3386                                .map(|outcome| {
3387                                    (outcome.rx_data, outcome.audit_seq, outcome.timestamp_ns)
3388                                })
3389                                .map_err(|error| match error {
3390                                    SpiTransmitError::Denied { denial, .. } => {
3391                                        denial_to_fidl(denial)
3392                                    }
3393                                    SpiTransmitError::Backend { .. } => {
3394                                        flab::OperationError::BackendFault
3395                                    }
3396                                })
3397                        }
3398                        Ok(_) => {
3399                            let now = now_ns();
3400                            match sessions.check_access(session_id, AccessClass::Protocol, now) {
3401                                Err(denial) => {
3402                                    let record = AuditRecord {
3403                                        session: Some(session_id),
3404                                        resource: Some(resource),
3405                                        operation: "spi_transmit",
3406                                        offset: None,
3407                                        decision: Decision::Denied(denial),
3408                                        status: OpStatus::Rejected,
3409                                        value: None,
3410                                        timestamp_ns: now,
3411                                        run_id: None,
3412                                        item_index: None,
3413                                    };
3414                                    audit.append(record);
3415                                    Err(denial_to_fidl(denial))
3416                                }
3417                                Ok(()) => {
3418                                    let session = sessions.session(session_id).unwrap();
3419                                    executor
3420                                        .spi_transmit(
3421                                            &session.policy,
3422                                            audit,
3423                                            session_id,
3424                                            resource,
3425                                            &tx_data,
3426                                        )
3427                                        .map(|outcome| {
3428                                            (
3429                                                outcome.rx_data,
3430                                                outcome.audit_seq,
3431                                                outcome.timestamp_ns,
3432                                            )
3433                                        })
3434                                        .map_err(|error| match error {
3435                                            SpiTransmitError::Denied { denial, .. } => {
3436                                                denial_to_fidl(denial)
3437                                            }
3438                                            SpiTransmitError::Backend { .. } => {
3439                                                flab::OperationError::BackendFault
3440                                            }
3441                                        })
3442                                }
3443                            }
3444                        }
3445                    }
3446                };
3447                let _ = responder.send(
3448                    result
3449                        .as_ref()
3450                        .map(|(data, seq, ts)| (data.as_slice(), *seq, *ts))
3451                        .map_err(|err| *err),
3452                );
3453            }
3454            flab::SpiEndpointRequest::_UnknownMethod { .. } => {}
3455        }
3456    }
3457}