Skip to main content

input_pipeline/
incoming.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
5use crate::Transport;
6use anyhow::Context;
7use fidl_fuchsia_io as fio;
8use fuchsia_component::client::Connect;
9use fuchsia_component::directory::{AsRefDirectory, Directory};
10
11#[cfg(feature = "dso")]
12pub use dso::*;
13
14#[cfg(not(feature = "dso"))]
15pub use elf::*;
16
17mod dso {
18    #![cfg(feature = "dso")]
19
20    use super::*;
21    use crate::DriverTransport;
22
23    #[derive(Clone)]
24    pub struct Incoming(std::sync::Arc<fdf_component::Incoming>);
25
26    impl Incoming {
27        pub fn new(incoming: std::sync::Arc<fdf_component::Incoming>) -> Self {
28            Self(incoming)
29        }
30
31        pub fn open_service<S: fidl::endpoints::ServiceMarker>(
32            &self,
33            marker: S,
34        ) -> Result<fuchsia_component::client::Service<S>, anyhow::Error> {
35            fuchsia_component::client::Service::open_from_dir_prefix(&*self.0, "svc", marker)
36                .context("Service::open_from_dir_prefix")
37        }
38
39        pub fn connect_protocol<T: Connect>(&self) -> Result<T, anyhow::Error> {
40            self.0.connect_protocol().context("connect_protocol")
41        }
42
43        pub fn connect_protocol_next<P: fidl_next::Discoverable>(
44            &self,
45        ) -> Result<fidl_next::ClientEnd<P, Transport>, anyhow::Error> {
46            self.0.connect_protocol_libasync_next().context("connect_protocol_next")
47        }
48
49        pub fn connect_protocol_next_at<P: fidl_next::Discoverable>(
50            dir: &impl AsRefDirectory,
51            path: &str,
52        ) -> Result<fidl_next::ClientEnd<P, Transport>, anyhow::Error> {
53            fdf_component::Incoming::connect_protocol_libasync_next_at(dir, path)
54                .context("connect_protocol_next_at")
55        }
56
57        pub fn connect_protocol_driver_transport<P: fidl_next::Discoverable>(
58            &self,
59        ) -> Result<fidl_next::ClientEnd<P, DriverTransport>, zx::Status> {
60            self.0.connect_protocol_driver_transport::<P, _>(fdf::CurrentDispatcher)
61        }
62
63        pub fn connect_protocol_driver_transport_at<P: fidl_next::Discoverable>(
64            dir: &impl AsRefDirectory,
65            path: &str,
66        ) -> Result<fidl_next::ClientEnd<P, DriverTransport>, zx::Status> {
67            fdf_component::Incoming::connect_protocol_driver_transport_at::<P, _>(
68                dir,
69                path,
70                fdf::CurrentDispatcher,
71            )
72        }
73    }
74
75    impl Directory for Incoming {
76        fn open(
77            &self,
78            path: &str,
79            flags: fio::Flags,
80            server_end: zx::Channel,
81        ) -> Result<(), anyhow::Error> {
82            self.0.open(path, flags, server_end)
83        }
84    }
85}
86
87mod elf {
88    #![cfg(not(feature = "dso"))]
89
90    use super::*;
91    use fuchsia_component::client::connect;
92
93    #[derive(Clone)]
94    pub struct Incoming;
95
96    impl Incoming {
97        pub fn new() -> Self {
98            Self {}
99        }
100
101        pub fn open_service<S: fidl::endpoints::ServiceMarker>(
102            &self,
103            marker: S,
104        ) -> Result<fuchsia_component::client::Service<S>, anyhow::Error> {
105            fuchsia_component::client::Service::open(marker).context("Service::open")
106        }
107
108        pub fn connect_protocol<T: Connect>(&self) -> Result<T, anyhow::Error> {
109            connect::connect_to_protocol::<T>()
110        }
111
112        pub fn connect_protocol_next<P: fidl_next::Discoverable>(
113            &self,
114        ) -> Result<fidl_next::ClientEnd<P, Transport>, anyhow::Error> {
115            let (client_end, server_end) = zx::Channel::create();
116            fdio::service_connect(&format!("/svc/{}", P::PROTOCOL_NAME), server_end)
117                .context("connect_protocol_next")?;
118            Ok(fidl_next::ClientEnd::<P, zx::Channel>::from_untyped(client_end))
119        }
120
121        pub fn connect_protocol_next_at<P: fidl_next::Discoverable>(
122            dir: &impl AsRefDirectory,
123            path: &str,
124        ) -> Result<fidl_next::ClientEnd<P, Transport>, anyhow::Error> {
125            let (client_end, server_end) = zx::Channel::create();
126            dir.as_ref_directory().open(path, fio::Flags::PROTOCOL_SERVICE, server_end)?;
127            Ok(fidl_next::ClientEnd::<P, zx::Channel>::from_untyped(client_end))
128        }
129    }
130
131    impl Directory for Incoming {
132        fn open(
133            &self,
134            path: &str,
135            flags: fio::Flags,
136            server_end: zx::Channel,
137        ) -> Result<(), anyhow::Error> {
138            let path = path.trim_start_matches('/');
139            let absolute_path = if path.starts_with("svc/")
140                || path == "svc"
141                || path.starts_with("pkg/")
142                || path == "pkg"
143                || path.starts_with("dev/")
144                || path == "dev"
145                || path.starts_with("tmp/")
146                || path == "tmp"
147                || path.starts_with("hub/")
148                || path == "hub"
149                || path.starts_with("data/")
150                || path == "data"
151                || path.starts_with("cache/")
152                || path == "cache"
153                || path.starts_with("config/")
154                || path == "config"
155                || path.starts_with("incoming/")
156                || path == "incoming"
157            {
158                format!("/{}", path)
159            } else if path.is_empty() {
160                "/".to_string()
161            } else {
162                // If it does not start with any recognized root namespace entry,
163                // assume it is a service/protocol under "/svc/".
164                format!("/svc/{}", path)
165            };
166
167            let namespace =
168                fdio::Namespace::installed().context("failed to get installed namespace")?;
169            namespace.open(&absolute_path, flags, server_end).context("Namespace::open")
170        }
171    }
172}
173
174impl AsRefDirectory for Incoming {
175    fn as_ref_directory(&self) -> &dyn fuchsia_component::directory::Directory {
176        self
177    }
178}