1use crate::builtin_devices::BuiltinDevVnode;
6use crate::class_names::{
7 CLASS_NAME_TO_SERVICE, CLASSES_THAT_ALLOW_TOPOLOGICAL_PATH, CLASSES_THAT_ASSUME_ORDERING, State,
8};
9use driver_manager_types::StartRequestReceiver;
10use fidl::endpoints::ServerEnd;
11use fidl_fuchsia_device as fdevice;
12use fidl_fuchsia_device_fs as fdevfs;
13use fidl_fuchsia_io as fio;
14use fuchsia_async as fasync;
15use fuchsia_sync::Mutex;
16use futures::StreamExt;
17use futures::channel::mpsc;
18use log::{debug, error, warn};
19use rand::{Rng, SeedableRng};
20use std::collections::HashMap;
21use std::sync::{Arc, Weak};
22use vfs::directory::entry::{DirectoryEntry, EntryInfo, GetEntryInfo, OpenRequest};
23use vfs::directory::entry_container::Directory;
24use vfs::directory::helper::DirectlyMutable;
25use vfs::directory::simple::Simple;
26use vfs::execution_scope::ExecutionScope;
27use vfs::path::Path;
28use vfs::remote::RemoteLike;
29use vfs::service::endpoint;
30use vfs::{ObjectRequestRef, pseudo_directory};
31
32mod builtin_devices;
33mod class_names;
34
35pub enum ConnectorMsg {
36 Controller(ServerEnd<fdevice::ControllerMarker>),
37 Protocol(zx::Channel),
38}
39
40pub type Connector = mpsc::UnboundedSender<ConnectorMsg>;
41
42pub enum OutgoingDirectoryMsg {
43 Connect(ServerEnd<fio::DirectoryMarker>),
44 AddServiceInstance(String, String, fio::DirectoryProxy),
45}
46
47pub type OutgoingDirectory = mpsc::UnboundedSender<OutgoingDirectoryMsg>;
48
49struct PathServer {
50 path: String,
51 scope: fasync::ScopeHandle,
52}
53
54impl PathServer {
55 fn new(path: String, scope: fasync::ScopeHandle) -> Self {
56 Self { path, scope }
57 }
58
59 fn serve(&self, channel: zx::Channel, class_name: &str) {
60 if !CLASSES_THAT_ALLOW_TOPOLOGICAL_PATH.contains(class_name) {
61 error!(
62 "Access to the topological path channel is not permitted for class {}",
63 class_name
64 );
65 return;
66 }
67 let mut stream = ServerEnd::<fdevfs::TopologicalPathMarker>::new(channel).into_stream();
68 let path = self.path.clone();
69 self.scope.spawn_local(async move {
70 while let Some(Ok(msg)) = stream.next().await {
71 match msg {
72 fdevfs::TopologicalPathRequest::GetTopologicalPath { responder } => {
73 let _ = responder.send(Ok(&path));
74 }
75 }
76 }
77 });
78 }
79}
80
81struct ServiceInfo {
82 parent_dir: Arc<Simple>,
83 member_name: String,
84}
85
86pub struct Devnode {
87 devfs: Weak<Devfs>,
88 parent: Weak<Simple>,
89 vnode: Arc<DevnodeVnode>,
90 name: String,
91 path_server: PathServer,
92 children: Arc<Simple>,
93 service_info: Mutex<Option<ServiceInfo>>,
94 #[allow(unused)]
95 scope: fasync::Scope,
96}
97
98impl Drop for Devnode {
99 fn drop(&mut self) {
100 let mut service_info = self.service_info.lock();
101 if let Some(info) = service_info.take() {
102 let _ = info.parent_dir.remove_entry(&info.member_name, false);
105 let _ = info.parent_dir.remove_entry(fdevfs::DEVICE_TOPOLOGY_NAME, false);
106 }
107 if let Some(parent_dir) = self.parent.upgrade() {
108 let _ = parent_dir.remove_entry(self.name.clone(), false);
109 }
110 }
111}
112
113impl Devnode {
114 fn new(
115 devfs: Weak<Devfs>,
116 parent: Weak<Simple>,
117 connector: Connector,
118 name: String,
119 path: &str,
120 class_name: &str,
121 ) -> Arc<Self> {
122 let scope = fasync::Scope::new_with_name("path_server");
123
124 let this = Arc::new_cyclic(|weak_self: &Weak<Devnode>| {
125 let children = Simple::new();
126 let vnode =
127 Arc::new(DevnodeVnode { connector: Some(connector), children: children.clone() });
128
129 let this = Self {
130 devfs,
131 parent,
132 vnode,
133 name,
134 path_server: PathServer::new(path.to_string(), scope.as_handle().clone()),
135 children,
136 service_info: Mutex::new(None),
137 scope,
138 };
139
140 let weak_self2 = weak_self.clone();
141 this.children
142 .add_entry(
143 fdevfs::DEVICE_CONTROLLER_NAME,
144 endpoint(move |_, channel| {
145 if let Some(this) = weak_self2.upgrade() {
146 let _ = this.vnode.connector.as_ref().unwrap().unbounded_send(
147 ConnectorMsg::Controller(channel.into_zx_channel().into()),
148 );
149 }
150 }),
151 )
152 .unwrap();
153
154 let weak_self2 = weak_self.clone();
155 this.children
156 .add_entry(
157 fdevfs::DEVICE_PROTOCOL_NAME,
158 endpoint(move |_, channel| {
159 if let Some(this) = weak_self2.upgrade() {
160 let _ = this
161 .vnode
162 .connector
163 .as_ref()
164 .unwrap()
165 .unbounded_send(ConnectorMsg::Protocol(channel.into()));
166 }
167 }),
168 )
169 .unwrap();
170
171 let class_name_clone = class_name.to_string();
172 let weak_self = weak_self.clone();
173 this.children
174 .add_entry(
175 fdevfs::DEVICE_TOPOLOGY_NAME,
176 endpoint(move |_, channel| {
177 if let Some(this) = weak_self.upgrade() {
178 this.path_server.serve(channel.into(), &class_name_clone);
179 }
180 }),
181 )
182 .unwrap();
183
184 this
185 });
186
187 if let Some(parent) = this.parent.upgrade() {
188 parent.add_entry(this.name.clone(), this.vnode.clone()).unwrap();
189 }
190 this
191 }
192
193 fn try_add_service(
194 self: &Arc<Self>,
195 class_name: &str,
196 connector: Connector,
197 instance_name: &str,
198 ) -> Result<(), zx::Status> {
199 let service_entry = if let Some(entry) = CLASS_NAME_TO_SERVICE.get(class_name) {
200 entry
201 } else {
202 return Ok(());
203 };
204
205 let devfs = self.devfs.upgrade().ok_or(zx::Status::BAD_STATE)?;
206
207 let instance_dir = Simple::new();
208 let handler = endpoint(move |_, channel| {
209 let _ = connector.unbounded_send(ConnectorMsg::Protocol(channel.into()));
210 });
211
212 let full_path = format!(
213 "svc/{}/{}/{}",
214 service_entry.service_name, instance_name, service_entry.member_name
215 );
216 if let Err(e) = instance_dir.add_entry(service_entry.member_name, handler) {
217 warn!("Failed to add service entry '{}' for class '{}': {}", full_path, class_name, e);
218 return Err(e);
219 }
220 debug!("Added service entry '{}' for class '{}'", full_path, class_name);
221
222 *self.service_info.lock() = Some(ServiceInfo {
223 parent_dir: instance_dir.clone(),
224 member_name: service_entry.member_name.to_string(),
225 });
226
227 let weak_self = Arc::downgrade(self);
229 let class_name_clone = class_name.to_string();
230 let topo_handler = endpoint(move |_, channel| {
231 if let Some(this) = weak_self.upgrade() {
232 this.path_server.serve(channel.into(), &class_name_clone);
233 }
234 });
235 let topo_full_path = format!("{}/{}", instance_name, fdevfs::DEVICE_TOPOLOGY_NAME);
236 if let Err(e) = instance_dir.add_entry(fdevfs::DEVICE_TOPOLOGY_NAME, topo_handler) {
237 warn!(
238 "Failed to add topological path service entry '{}' for class '{}': {}",
239 topo_full_path, class_name, e
240 );
241 let _ = instance_dir.remove_entry(service_entry.member_name, false);
242 return Err(e);
243 }
244
245 let instance_dir = vfs::directory::serve(
246 instance_dir,
247 ExecutionScope::new(),
248 fio::PERM_READABLE | fio::PERM_WRITABLE,
249 );
250
251 if let Err(e) = devfs.outgoing.unbounded_send(OutgoingDirectoryMsg::AddServiceInstance(
252 service_entry.service_name.to_string(),
253 instance_name.to_string(),
254 instance_dir,
255 )) {
256 warn!(
257 "Failed to add instance to outgoing directory '{}' for class '{}': {}",
258 topo_full_path, class_name, e
259 );
260 return Err(zx::Status::BAD_STATE);
261 }
262
263 Ok(())
264 }
265
266 fn add_child(
267 self: &Arc<Self>,
268 name: &str,
269 class_name: Option<&str>,
270 connector: Connector,
271 ) -> Result<DevfsDevice, zx::Status> {
272 if self.children.get_entry(name).is_ok() {
273 warn!("rejecting duplicate device name '{}'", name);
274 return Err(zx::Status::ALREADY_EXISTS);
275 }
276
277 let mut child = DevfsDevice::new();
278 let child_path = format!("{}/{}", self.path_server.path, name);
279 if let Some(class_name) = class_name
280 && let Some(service_entry) = CLASS_NAME_TO_SERVICE.get(class_name)
281 {
282 let instance_name = self.devfs.upgrade().unwrap().make_instance_name(class_name)?;
283 if matches!(service_entry.state, State::Devfs | State::DevfsAndService) {
284 let devfs = self.devfs.upgrade().unwrap();
285 let class_dir = devfs.class_dirs.get(class_name).unwrap();
286 child.protocol = Some(Devnode::new(
287 self.devfs.clone(),
288 Arc::downgrade(class_dir),
289 connector.clone(),
290 instance_name.clone(),
291 &child_path,
292 class_name,
293 ));
294 }
295
296 if matches!(service_entry.state, State::DevfsAndService) {
297 let protocol_node = child.protocol.as_ref().unwrap().clone();
298 protocol_node.try_add_service(class_name, connector.clone(), &instance_name)?;
299 }
300 }
301
302 child.topological = Some(TopologicalDevnode::Devnode(Devnode::new(
303 self.devfs.clone(),
304 Arc::downgrade(&self.children),
305 connector,
306 name.to_string(),
307 &child_path,
308 class_name.unwrap_or(""),
309 )));
310
311 Ok(child)
312 }
313}
314
315struct DevnodeVnode {
316 connector: Option<Connector>,
317 children: Arc<Simple>,
318}
319
320impl RemoteLike for DevnodeVnode {
321 fn open(
322 self: Arc<DevnodeVnode>,
323 scope: ExecutionScope,
324 path: Path,
325 flags: fio::Flags,
326 object_request: ObjectRequestRef<'_>,
327 ) -> Result<(), zx::Status> {
328 if flags.contains(fio::Flags::PROTOCOL_DIRECTORY)
329 || flags.contains(fio::Flags::PROTOCOL_NODE)
330 || !path.is_empty()
331 {
332 self.children.clone().open(scope, path, flags, object_request)
333 } else if let Some(ref connector) = self.connector
334 && flags.contains(fio::Flags::PROTOCOL_SERVICE)
335 {
336 let _ = connector
338 .unbounded_send(ConnectorMsg::Protocol(object_request.take().into_channel()));
339 Ok(())
340 } else {
341 Err(zx::Status::NOT_FOUND)
342 }
343 }
344}
345
346impl DirectoryEntry for DevnodeVnode {
347 fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), zx::Status> {
348 request.open_remote(self)
349 }
350}
351
352impl GetEntryInfo for DevnodeVnode {
353 fn entry_info(&self) -> EntryInfo {
354 EntryInfo::new(fio::INO_UNKNOWN, fio::DirentType::Directory)
355 }
356}
357
358#[derive(Clone)]
359pub struct RootDevnode {
360 children: Arc<Simple>,
361 devfs: Weak<Devfs>,
362}
363
364impl RootDevnode {
365 fn add_child(
366 &self,
367 name: &str,
368 class_name: Option<&str>,
369 connector: Connector,
370 ) -> Result<DevfsDevice, zx::Status> {
371 let devfs = self.devfs.upgrade().unwrap();
372
373 let mut child = DevfsDevice::new();
374 let child_path = format!("/{}", name);
375 if let Some(class_name) = class_name
376 && let Some(service_entry) = CLASS_NAME_TO_SERVICE.get(class_name)
377 {
378 let instance_name = devfs.make_instance_name(class_name)?;
379 if matches!(service_entry.state, State::Devfs | State::DevfsAndService) {
380 let class_dir = devfs.class_dirs.get(class_name).unwrap();
381 child.protocol = Some(Devnode::new(
382 self.devfs.clone(),
383 Arc::downgrade(class_dir),
384 connector.clone(),
385 instance_name.clone(),
386 &child_path,
387 class_name,
388 ));
389 }
390
391 if matches!(service_entry.state, State::DevfsAndService) {
392 let protocol_node = child.protocol.as_ref().unwrap().clone();
393 protocol_node.try_add_service(class_name, connector.clone(), &instance_name)?;
394 }
395 }
396
397 child.topological = Some(TopologicalDevnode::Devnode(Devnode::new(
398 self.devfs.clone(),
399 Arc::downgrade(&self.children),
400 connector,
401 name.to_string(),
402 &child_path,
403 class_name.unwrap_or(""),
404 )));
405
406 Ok(child)
407 }
408}
409
410#[derive(Clone)]
411pub enum TopologicalDevnode {
412 Root(RootDevnode),
413 Devnode(Arc<Devnode>),
414}
415
416impl TopologicalDevnode {
417 pub fn add_child(
418 &self,
419 name: &str,
420 class_name: Option<&str>,
421 connector: Connector,
422 ) -> Result<DevfsDevice, zx::Status> {
423 match self {
424 Self::Root(devnode) => devnode.add_child(name, class_name, connector),
425 Self::Devnode(devnode) => devnode.add_child(name, class_name, connector),
426 }
427 }
428}
429
430#[derive(Clone)]
431pub struct DevfsDevice {
432 pub topological: Option<TopologicalDevnode>,
433 pub protocol: Option<Arc<Devnode>>,
434}
435
436impl DevfsDevice {
437 pub fn new() -> Self {
438 Self { topological: None, protocol: None }
439 }
440}
441
442impl Default for DevfsDevice {
443 fn default() -> Self {
444 Self::new()
445 }
446}
447
448pub struct Devfs {
449 root: Arc<Simple>,
450 class_dirs: HashMap<String, Arc<Simple>>,
451 device_number_generator: Mutex<rand::rngs::StdRng>,
452 classes_that_assume_ordering: Mutex<HashMap<String, u32>>,
453 outgoing: OutgoingDirectory,
454 component_controller_proxy: Mutex<Option<fidl_fuchsia_component::ControllerProxy>>,
455}
456
457impl Devfs {
458 pub fn new(outgoing: OutgoingDirectory) -> Arc<Self> {
459 let class = Simple::new();
460 let root = pseudo_directory!(
461 "class" => class.clone(),
462 "null" => BuiltinDevVnode::new(true),
463 "zero" => BuiltinDevVnode::new(false),
464 "builtin" => pseudo_directory!(
465 "null" => BuiltinDevVnode::new(true),
466 "zero" => BuiltinDevVnode::new(false),
467 ),
468 );
469
470 let mut class_dirs = HashMap::new();
471 for (class_name, _) in &CLASS_NAME_TO_SERVICE {
472 let dir = Simple::new();
473 class.add_entry(*class_name, dir.clone()).unwrap();
474 class_dirs.insert(class_name.to_string(), dir);
475 }
476
477 let mut ordering = HashMap::new();
478 for class_name in CLASSES_THAT_ASSUME_ORDERING.iter() {
479 ordering.insert(class_name.to_string(), 0);
480 }
481
482 Arc::new(Self {
483 root,
484 class_dirs,
485 device_number_generator: Mutex::new(rand::rngs::StdRng::from_seed(Default::default())),
486 classes_that_assume_ordering: Mutex::new(ordering),
487 outgoing,
488 component_controller_proxy: Mutex::new(None),
489 })
490 }
491
492 pub fn root_node(self: &Arc<Self>) -> TopologicalDevnode {
493 TopologicalDevnode::Root(RootDevnode {
494 children: self.root.clone(),
495 devfs: Arc::downgrade(self),
496 })
497 }
498
499 pub fn serve(&self) -> fio::DirectoryProxy {
500 vfs::directory::serve(
501 self.root.clone(),
502 ExecutionScope::new(),
503 fio::PERM_READABLE | fio::PERM_WRITABLE,
504 )
505 }
506
507 pub fn set_component_controller_proxy(
508 &self,
509 controller: fidl_fuchsia_component::ControllerProxy,
510 ) {
511 let mut proxy = self.component_controller_proxy.lock();
512 *proxy = Some(controller);
513 }
514
515 pub async fn send_start_request(
516 &self,
517 handle: fidl_fuchsia_process::HandleInfo,
518 ) -> Result<(), zx::Status> {
519 let start_child_args = fidl_fuchsia_component::StartChildArgs {
520 numbered_handles: Some(vec![handle]),
521 ..Default::default()
522 };
523 let (_, server_end) = fidl::endpoints::create_endpoints();
524
525 let proxy = self.component_controller_proxy.lock().clone().ok_or_else(|| {
526 error!("no component controller proxy");
527 zx::Status::INTERNAL
528 })?;
529
530 proxy
531 .start(start_child_args, server_end)
532 .await
533 .map_err(|e| {
534 error!("Failed to start driver for devfs: {}", e);
535 zx::Status::INTERNAL
536 })?
537 .map_err(|e| {
538 error!("Failed to start driver for devfs: {:?}", e);
539 zx::Status::INTERNAL
540 })?;
541 Ok(())
542 }
543
544 pub async fn attach_component(
545 &self,
546 handle: fidl_fuchsia_process::HandleInfo,
547 mut receiver: StartRequestReceiver,
548 ) -> Result<(), zx::Status> {
549 self.send_start_request(handle).await?;
550 let start_request = receiver.next().await.ok_or(zx::Status::TIMED_OUT)??;
551 let start_info = start_request.info;
552 let controller = start_request.controller;
553
554 if let Some(outgoing_dir) = start_info.outgoing_dir {
555 let _ = self.outgoing.unbounded_send(OutgoingDirectoryMsg::Connect(outgoing_dir));
556 } else {
557 warn!("No outgoing dir available for devfs component.");
558 }
559 fasync::Task::local(async move {
560 let (mut stream, handle) = controller.into_stream_and_control_handle();
561 if let Some(Ok(_)) = stream.next().await {
562 let _ = handle
563 .send_on_stop(fidl_fuchsia_component_runner::ComponentStopInfo {
564 ..Default::default()
565 })
566 .inspect_err(|e| {
567 error!("Failed to stop driver for devfs: {}", e);
568 });
569 }
570 })
571 .detach();
572 Ok(())
573 }
574
575 pub fn make_instance_name(&self, class_name: &str) -> Result<String, zx::Status> {
576 if !CLASS_NAME_TO_SERVICE.contains_key(class_name) {
577 return Err(zx::Status::NOT_FOUND);
578 }
579 if let Some(next_id) = self.classes_that_assume_ordering.lock().get_mut(class_name) {
580 let id = *next_id;
581 *next_id += 1;
582 Ok(format!("{:03}", id))
583 } else {
584 let mut rng = self.device_number_generator.lock();
585 Ok(format!("{}", rng.random::<u32>()))
586 }
587 }
588}