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::{self, HandleBased};
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::handle::HandleBased;
52    use fidl_fuchsia_component_sandbox as fsandbox;
53
54    // Tests converting the Handle to FIDL and back.
55    #[fuchsia::test]
56    async fn handle_into_fidl() {
57        let event = zx::Event::create();
58        let expected_koid = event.koid().unwrap();
59
60        let handle = Handle::new(event.into_handle());
61
62        // Convert the OneShotHandle to FIDL and back.
63        let fidl_capability: fsandbox::Capability =
64            handle.into_fsandbox_capability(WeakInstanceToken::new_invalid());
65        assert_matches!(&fidl_capability, fsandbox::Capability::Handle(_));
66
67        let any: Capability = fidl_capability.try_into().unwrap();
68        let handle = assert_matches!(any, Capability::Handle(h) => h);
69
70        // Get the handle.
71        let handle: zx::NullableHandle = handle.take().unwrap();
72
73        // The handle should be for same Event that was in the original OneShotHandle.
74        let got_koid = handle.koid().unwrap();
75        assert_eq!(got_koid, expected_koid);
76    }
77
78    /// Tests that a Handle can be cloned by duplicating the handle.
79    #[fuchsia::test]
80    async fn try_clone() {
81        let event = zx::Event::create();
82        let expected_koid = event.koid().unwrap();
83
84        let handle = Handle::new(event.into_handle());
85        let handle = handle.duplicate().unwrap();
86
87        let got_koid = handle.koid().unwrap();
88        assert_eq!(got_koid, expected_koid);
89
90        let (ch, _) = zx::Channel::create();
91        let handle = Handle::new(ch.into_handle());
92        assert_matches!(handle.try_clone(), Err(()));
93    }
94}