sandbox/
handle.rs

1// Copyright 2023 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
5use crate::CapabilityBound;
6use fidl::handle::{self, HandleBased};
7
8/// A capability that wraps a single Zircon handle.
9#[derive(Debug)]
10pub struct Handle(handle::NullableHandle);
11
12impl Handle {
13    /// Creates a new [Handle] containing a Zircon `handle`.
14    pub fn new(handle: handle::NullableHandle) -> Self {
15        Self(handle)
16    }
17}
18
19impl From<handle::NullableHandle> for Handle {
20    fn from(handle: handle::NullableHandle) -> Self {
21        Self(handle)
22    }
23}
24
25impl CapabilityBound for Handle {
26    fn debug_typename() -> &'static str {
27        "Handle"
28    }
29}
30
31impl Handle {
32    pub fn try_clone(&self) -> Result<Self, ()> {
33        Ok(Self(self.0.duplicate_handle(fidl::Rights::SAME_RIGHTS).map_err(|_| ())?))
34    }
35}
36
37impl From<Handle> for handle::NullableHandle {
38    fn from(value: Handle) -> Self {
39        value.0
40    }
41}
42
43#[cfg(target_os = "fuchsia")]
44#[cfg(test)]
45mod tests {
46    use super::*;
47    use crate::fidl::IntoFsandboxCapability;
48    use crate::{Capability, WeakInstanceToken};
49    use assert_matches::assert_matches;
50    use fidl::handle::{AsHandleRef, HandleBased};
51    use fidl_fuchsia_component_sandbox as fsandbox;
52
53    // Tests converting the Handle to FIDL and back.
54    #[fuchsia::test]
55    async fn handle_into_fidl() {
56        let event = zx::Event::create();
57        let expected_koid = event.get_koid().unwrap();
58
59        let handle = Handle::from(event.into_handle());
60
61        // Convert the OneShotHandle to FIDL and back.
62        let fidl_capability: fsandbox::Capability =
63            handle.into_fsandbox_capability(WeakInstanceToken::new_invalid());
64        assert_matches!(&fidl_capability, fsandbox::Capability::Handle(_));
65
66        let any: Capability = fidl_capability.try_into().unwrap();
67        let handle = assert_matches!(any, Capability::Handle(h) => h);
68
69        // Get the handle.
70        let handle: zx::NullableHandle = handle.into();
71
72        // The handle should be for same Event that was in the original OneShotHandle.
73        let got_koid = handle.get_koid().unwrap();
74        assert_eq!(got_koid, expected_koid);
75    }
76
77    /// Tests that a Handle can be cloned by duplicating the handle.
78    #[fuchsia::test]
79    async fn try_clone() {
80        let event = zx::Event::create();
81        let expected_koid = event.get_koid().unwrap();
82
83        let handle = Handle::from(event.into_handle());
84        let handle = handle.try_clone().unwrap();
85        let handle: zx::NullableHandle = handle.into();
86
87        let got_koid = handle.get_koid().unwrap();
88        assert_eq!(got_koid, expected_koid);
89
90        let (ch, _) = zx::Channel::create();
91        let handle = Handle::from(ch.into_handle());
92        assert_matches!(handle.try_clone(), Err(()));
93    }
94}