Skip to main content

runtime_capabilities/
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;
7use fuchsia_sync::Mutex;
8use std::sync::Arc;
9
10/// A capability that wraps a single Zircon handle.
11#[derive(Debug, Clone)]
12pub struct Handle(Arc<Mutex<Option<handle::NullableHandle>>>);
13
14impl Handle {
15    /// Creates a new [Handle] containing a Zircon `handle`.
16    pub fn new(handle: handle::NullableHandle) -> Self {
17        Self(Arc::new(Mutex::new(Some(handle))))
18    }
19
20    /// Gets a duplicate of the inner handle. Returns None if the handle has been taken or the
21    /// duplicate operation fails.
22    pub fn duplicate(&self) -> Option<handle::NullableHandle> {
23        self.0.lock().as_ref().and_then(|h| h.duplicate_handle(handle::Rights::SAME_RIGHTS).ok())
24    }
25
26    /// Removes the inner handle and returns it.
27    pub fn take(&self) -> Option<handle::NullableHandle> {
28        self.0.lock().take()
29    }
30}
31
32impl CapabilityBound for Handle {
33    fn debug_typename() -> &'static str {
34        "Handle"
35    }
36}
37
38impl Handle {
39    pub fn try_clone(&self) -> Result<Self, ()> {
40        self.duplicate().map(Self::new).ok_or(())
41    }
42}
43
44#[cfg(target_os = "fuchsia")]
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use crate::fidl::IntoFsandboxCapability;
49    use crate::{Capability, WeakInstanceToken};
50    use assert_matches::assert_matches;
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.koid().unwrap();
58
59        let handle = Handle::new(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.take().unwrap();
71
72        // The handle should be for same Event that was in the original OneShotHandle.
73        let got_koid = handle.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.koid().unwrap();
82
83        let handle = Handle::new(event.into_handle());
84        let handle = handle.duplicate().unwrap();
85
86        let got_koid = handle.koid().unwrap();
87        assert_eq!(got_koid, expected_koid);
88
89        let (ch, _) = zx::Channel::create();
90        let handle = Handle::new(ch.into_handle());
91        assert_matches!(handle.try_clone(), Err(()));
92    }
93}