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 fuchsia_sync::Mutex;
12use futures::StreamExt;
13use futures::channel::mpsc;
14use log::{debug, error, warn};
15use rand::{Rng, SeedableRng};
16use std::collections::HashMap;
17use std::sync::{Arc, Weak};
18use vfs::directory::entry::{DirectoryEntry, EntryInfo, GetEntryInfo, OpenRequest};
19use vfs::directory::entry_container::Directory;
20use vfs::directory::helper::DirectlyMutable;
21use vfs::directory::simple::Simple;
22use vfs::execution_scope::ExecutionScope;
23use vfs::path::Path;
24use vfs::remote::RemoteLike;
25use vfs::service::endpoint;
26use vfs::{ObjectRequestRef, pseudo_directory};
27use {
28 fidl_fuchsia_device as fdevice, fidl_fuchsia_device_fs as fdevfs, fidl_fuchsia_io as fio,
29 fuchsia_async as fasync,
30};
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 =
246 vfs::directory::serve(instance_dir, fio::PERM_READABLE | fio::PERM_WRITABLE);
247
248 if let Err(e) = devfs.outgoing.unbounded_send(OutgoingDirectoryMsg::AddServiceInstance(
249 service_entry.service_name.to_string(),
250 instance_name.to_string(),
251 instance_dir,
252 )) {
253 warn!(
254 "Failed to add instance to outgoing directory '{}' for class '{}': {}",
255 topo_full_path, class_name, e
256 );
257 return Err(zx::Status::BAD_STATE);
258 }
259
260 Ok(())
261 }
262
263 fn add_child(
264 self: &Arc<Self>,
265 name: &str,
266 class_name: Option<&str>,
267 connector: Connector,
268 ) -> Result<DevfsDevice, zx::Status> {
269 if self.children.get_entry(name).is_ok() {
270 warn!("rejecting duplicate device name '{}'", name);
271 return Err(zx::Status::ALREADY_EXISTS);
272 }
273
274 let mut child = DevfsDevice::new();
275 let child_path = format!("{}/{}", self.path_server.path, name);
276 if let Some(class_name) = class_name
277 && let Some(service_entry) = CLASS_NAME_TO_SERVICE.get(class_name)
278 {
279 let instance_name = self.devfs.upgrade().unwrap().make_instance_name(class_name)?;
280 if matches!(service_entry.state, State::Devfs | State::DevfsAndService) {
281 let devfs = self.devfs.upgrade().unwrap();
282 let class_dir = devfs.class_dirs.get(class_name).unwrap();
283 child.protocol = Some(Devnode::new(
284 self.devfs.clone(),
285 Arc::downgrade(class_dir),
286 connector.clone(),
287 instance_name.clone(),
288 &child_path,
289 class_name,
290 ));
291 }
292
293 if matches!(service_entry.state, State::DevfsAndService) {
294 let protocol_node = child.protocol.as_ref().unwrap().clone();
295 protocol_node.try_add_service(class_name, connector.clone(), &instance_name)?;
296 }
297 }
298
299 child.topological = Some(TopologicalDevnode::Devnode(Devnode::new(
300 self.devfs.clone(),
301 Arc::downgrade(&self.children),
302 connector,
303 name.to_string(),
304 &child_path,
305 class_name.unwrap_or(""),
306 )));
307
308 Ok(child)
309 }
310}
311
312struct DevnodeVnode {
313 connector: Option<Connector>,
314 children: Arc<Simple>,
315}
316
317impl RemoteLike for DevnodeVnode {
318 fn open(
319 self: Arc<DevnodeVnode>,
320 scope: ExecutionScope,
321 path: Path,
322 flags: fio::Flags,
323 object_request: ObjectRequestRef<'_>,
324 ) -> Result<(), zx::Status> {
325 if flags.contains(fio::Flags::PROTOCOL_DIRECTORY)
326 || flags.contains(fio::Flags::PROTOCOL_NODE)
327 || !path.is_empty()
328 {
329 self.children.clone().open(scope, path, flags, object_request)
330 } else if let Some(ref connector) = self.connector
331 && flags.contains(fio::Flags::PROTOCOL_SERVICE)
332 {
333 let _ = connector
335 .unbounded_send(ConnectorMsg::Protocol(object_request.take().into_channel()));
336 Ok(())
337 } else {
338 Err(zx::Status::NOT_FOUND)
339 }
340 }
341}
342
343impl DirectoryEntry for DevnodeVnode {
344 fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), zx::Status> {
345 request.open_remote(self)
346 }
347}
348
349impl GetEntryInfo for DevnodeVnode {
350 fn entry_info(&self) -> EntryInfo {
351 EntryInfo::new(fio::INO_UNKNOWN, fio::DirentType::Directory)
352 }
353}
354
355#[derive(Clone)]
356pub struct RootDevnode {
357 children: Arc<Simple>,
358 devfs: Weak<Devfs>,
359}
360
361impl RootDevnode {
362 fn add_child(
363 &self,
364 name: &str,
365 class_name: Option<&str>,
366 connector: Connector,
367 ) -> Result<DevfsDevice, zx::Status> {
368 let devfs = self.devfs.upgrade().unwrap();
369
370 let mut child = DevfsDevice::new();
371 let child_path = format!("/{}", name);
372 if let Some(class_name) = class_name
373 && let Some(service_entry) = CLASS_NAME_TO_SERVICE.get(class_name)
374 {
375 let instance_name = devfs.make_instance_name(class_name)?;
376 if matches!(service_entry.state, State::Devfs | State::DevfsAndService) {
377 let class_dir = devfs.class_dirs.get(class_name).unwrap();
378 child.protocol = Some(Devnode::new(
379 self.devfs.clone(),
380 Arc::downgrade(class_dir),
381 connector.clone(),
382 instance_name.clone(),
383 &child_path,
384 class_name,
385 ));
386 }
387
388 if matches!(service_entry.state, State::DevfsAndService) {
389 let protocol_node = child.protocol.as_ref().unwrap().clone();
390 protocol_node.try_add_service(class_name, connector.clone(), &instance_name)?;
391 }
392 }
393
394 child.topological = Some(TopologicalDevnode::Devnode(Devnode::new(
395 self.devfs.clone(),
396 Arc::downgrade(&self.children),
397 connector,
398 name.to_string(),
399 &child_path,
400 class_name.unwrap_or(""),
401 )));
402
403 Ok(child)
404 }
405}
406
407#[derive(Clone)]
408pub enum TopologicalDevnode {
409 Root(RootDevnode),
410 Devnode(Arc<Devnode>),
411}
412
413impl TopologicalDevnode {
414 pub fn add_child(
415 &self,
416 name: &str,
417 class_name: Option<&str>,
418 connector: Connector,
419 ) -> Result<DevfsDevice, zx::Status> {
420 match self {
421 Self::Root(devnode) => devnode.add_child(name, class_name, connector),
422 Self::Devnode(devnode) => devnode.add_child(name, class_name, connector),
423 }
424 }
425}
426
427#[derive(Clone)]
428pub struct DevfsDevice {
429 pub topological: Option<TopologicalDevnode>,
430 pub protocol: Option<Arc<Devnode>>,
431}
432
433impl DevfsDevice {
434 pub fn new() -> Self {
435 Self { topological: None, protocol: None }
436 }
437}
438
439impl Default for DevfsDevice {
440 fn default() -> Self {
441 Self::new()
442 }
443}
444
445pub struct Devfs {
446 root: Arc<Simple>,
447 class_dirs: HashMap<String, Arc<Simple>>,
448 device_number_generator: Mutex<rand::rngs::StdRng>,
449 classes_that_assume_ordering: Mutex<HashMap<String, u32>>,
450 outgoing: OutgoingDirectory,
451 component_controller_proxy: Mutex<Option<fidl_fuchsia_component::ControllerProxy>>,
452}
453
454impl Devfs {
455 pub fn new(outgoing: OutgoingDirectory) -> Arc<Self> {
456 let class = Simple::new();
457 let root = pseudo_directory!(
458 "class" => class.clone(),
459 "null" => BuiltinDevVnode::new(true),
460 "zero" => BuiltinDevVnode::new(false),
461 "builtin" => pseudo_directory!(
462 "null" => BuiltinDevVnode::new(true),
463 "zero" => BuiltinDevVnode::new(false),
464 ),
465 );
466
467 let mut class_dirs = HashMap::new();
468 for (class_name, _) in &CLASS_NAME_TO_SERVICE {
469 let dir = Simple::new();
470 class.add_entry(*class_name, dir.clone()).unwrap();
471 class_dirs.insert(class_name.to_string(), dir);
472 }
473
474 let mut ordering = HashMap::new();
475 for class_name in CLASSES_THAT_ASSUME_ORDERING.iter() {
476 ordering.insert(class_name.to_string(), 0);
477 }
478
479 Arc::new(Self {
480 root,
481 class_dirs,
482 device_number_generator: Mutex::new(rand::rngs::StdRng::from_seed(Default::default())),
483 classes_that_assume_ordering: Mutex::new(ordering),
484 outgoing,
485 component_controller_proxy: Mutex::new(None),
486 })
487 }
488
489 pub fn root_node(self: &Arc<Self>) -> TopologicalDevnode {
490 TopologicalDevnode::Root(RootDevnode {
491 children: self.root.clone(),
492 devfs: Arc::downgrade(self),
493 })
494 }
495
496 pub fn serve(&self) -> fio::DirectoryProxy {
497 vfs::directory::serve(self.root.clone(), fio::PERM_READABLE | fio::PERM_WRITABLE)
498 }
499
500 pub fn set_component_controller_proxy(
501 &self,
502 controller: fidl_fuchsia_component::ControllerProxy,
503 ) {
504 let mut proxy = self.component_controller_proxy.lock();
505 *proxy = Some(controller);
506 }
507
508 pub async fn send_start_request(
509 &self,
510 handle: fidl_fuchsia_process::HandleInfo,
511 ) -> Result<(), zx::Status> {
512 let start_child_args = fidl_fuchsia_component::StartChildArgs {
513 numbered_handles: Some(vec![handle]),
514 ..Default::default()
515 };
516 let (_, server_end) = fidl::endpoints::create_endpoints();
517
518 let proxy = self.component_controller_proxy.lock().clone().ok_or_else(|| {
519 error!("no component controller proxy");
520 zx::Status::INTERNAL
521 })?;
522
523 proxy
524 .start(start_child_args, server_end)
525 .await
526 .map_err(|e| {
527 error!("Failed to start driver for devfs: {}", e);
528 zx::Status::INTERNAL
529 })?
530 .map_err(|e| {
531 error!("Failed to start driver for devfs: {:?}", e);
532 zx::Status::INTERNAL
533 })?;
534 Ok(())
535 }
536
537 pub async fn attach_component(
538 &self,
539 handle: fidl_fuchsia_process::HandleInfo,
540 mut receiver: StartRequestReceiver,
541 ) -> Result<(), zx::Status> {
542 self.send_start_request(handle).await?;
543 let start_request = receiver.next().await.ok_or(zx::Status::TIMED_OUT)??;
544 let start_info = start_request.info;
545 let controller = start_request.controller;
546
547 if let Some(outgoing_dir) = start_info.outgoing_dir {
548 let _ = self.outgoing.unbounded_send(OutgoingDirectoryMsg::Connect(outgoing_dir));
549 } else {
550 warn!("No outgoing dir available for devfs component.");
551 }
552 fasync::Task::local(async move {
553 let (mut stream, handle) = controller.into_stream_and_control_handle();
554 if let Some(Ok(_)) = stream.next().await {
555 let _ = handle
556 .send_on_stop(fidl_fuchsia_component_runner::ComponentStopInfo {
557 ..Default::default()
558 })
559 .inspect_err(|e| {
560 error!("Failed to stop driver for devfs: {}", e);
561 });
562 }
563 })
564 .detach();
565 Ok(())
566 }
567
568 pub fn make_instance_name(&self, class_name: &str) -> Result<String, zx::Status> {
569 if !CLASS_NAME_TO_SERVICE.contains_key(class_name) {
570 return Err(zx::Status::NOT_FOUND);
571 }
572 if let Some(next_id) = self.classes_that_assume_ordering.lock().get_mut(class_name) {
573 let id = *next_id;
574 *next_id += 1;
575 Ok(format!("{:03}", id))
576 } else {
577 let mut rng = self.device_number_generator.lock();
578 Ok(format!("{}", rng.random::<u32>()))
579 }
580 }
581}