1use anyhow::format_err;
6use async_trait::async_trait;
7use cm_rust::ComponentDecl;
8use cm_types::{Name, Url};
9use errors::ModelError;
10use futures::channel::oneshot;
11use futures::lock::Mutex;
12use log::warn;
13use moniker::{ExtendedMoniker, Moniker};
14use sandbox::{Connector, Receiver, WeakInstanceToken};
15use std::collections::HashMap;
16use std::fmt;
17use std::sync::{Arc, Mutex as StdMutex, Weak};
18use {
19 fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_runner as fcrunner,
20 fidl_fuchsia_io as fio,
21};
22
23pub trait HasEventType {
24 fn event_type(&self) -> EventType;
25}
26
27#[async_trait]
30pub trait TransferEvent {
31 async fn transfer(&self) -> Self;
32}
33
34#[derive(Clone, Debug, Eq, PartialEq, Hash)]
35pub enum EventType {
36 CapabilityRequested,
39 Destroyed,
42 Resolved,
44 Started,
46 Stopped,
49 DebugStarted,
52 Unresolved,
54}
55
56impl EventType {
57 fn as_str(&self) -> &str {
58 match self {
59 EventType::CapabilityRequested => "capability_requested",
60 EventType::Destroyed => "destroyed",
61 EventType::Resolved => "resolved",
62 EventType::Started => "started",
63 EventType::Stopped => "stopped",
64 EventType::DebugStarted => "debug_started",
65 EventType::Unresolved => "unresolved",
66 }
67 }
68
69 pub fn values() -> Vec<EventType> {
71 vec![
72 EventType::CapabilityRequested,
73 EventType::Destroyed,
74 EventType::Resolved,
75 EventType::Started,
76 EventType::Stopped,
77 EventType::DebugStarted,
78 EventType::Unresolved,
79 ]
80 }
81}
82
83impl From<EventType> for Name {
84 fn from(event_type: EventType) -> Name {
85 event_type.as_str().parse().unwrap()
86 }
87}
88
89impl fmt::Display for EventType {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 write!(f, "{}", self.as_str())
92 }
93}
94
95impl TryFrom<String> for EventType {
96 type Error = anyhow::Error;
97 fn try_from(string: String) -> Result<EventType, Self::Error> {
98 for value in EventType::values() {
99 if value.as_str() == string {
100 return Ok(value);
101 }
102 }
103 Err(format_err!("invalid string for event type: {:?}", string))
104 }
105}
106
107impl HasEventType for EventPayload {
108 fn event_type(&self) -> EventType {
109 match self {
110 EventPayload::CapabilityRequested { .. } => EventType::CapabilityRequested,
111 EventPayload::Destroyed => EventType::Destroyed,
112 EventPayload::Resolved { .. } => EventType::Resolved,
113 EventPayload::Started { .. } => EventType::Started,
114 EventPayload::Stopped { .. } => EventType::Stopped,
115 EventPayload::DebugStarted { .. } => EventType::DebugStarted,
116 EventPayload::Unresolved => EventType::Unresolved,
117 }
118 }
119}
120
121impl From<fcomponent::EventType> for EventType {
122 fn from(fidl_event_type: fcomponent::EventType) -> Self {
123 match fidl_event_type {
124 fcomponent::EventType::CapabilityRequested => EventType::CapabilityRequested,
125 fcomponent::EventType::DirectoryReady => unreachable!("This isn't used anymore"),
126 fcomponent::EventType::Discovered => unreachable!("This isn't used anymore"),
127 fcomponent::EventType::Destroyed => EventType::Destroyed,
128 fcomponent::EventType::Resolved => EventType::Resolved,
129 fcomponent::EventType::Started => EventType::Started,
130 fcomponent::EventType::Stopped => EventType::Stopped,
131 fcomponent::EventType::DebugStarted => EventType::DebugStarted,
132 fcomponent::EventType::Unresolved => EventType::Unresolved,
133 }
134 }
135}
136
137impl From<EventType> for fcomponent::EventType {
138 fn from(event_type: EventType) -> Self {
139 match event_type {
140 EventType::CapabilityRequested => fcomponent::EventType::CapabilityRequested,
141 EventType::Destroyed => fcomponent::EventType::Destroyed,
142 EventType::Resolved => fcomponent::EventType::Resolved,
143 EventType::Started => fcomponent::EventType::Started,
144 EventType::Stopped => fcomponent::EventType::Stopped,
145 EventType::DebugStarted => fcomponent::EventType::DebugStarted,
146 EventType::Unresolved => fcomponent::EventType::Unresolved,
147 }
148 }
149}
150
151#[async_trait]
160pub trait Hook: Send + Sync {
161 async fn on(self: Arc<Self>, event: &Event) -> Result<(), ModelError>;
162}
163
164#[derive(Clone)]
169pub struct HooksRegistration {
170 events: Vec<EventType>,
171 callback: Weak<dyn Hook>,
172}
173
174impl HooksRegistration {
175 pub fn new(
176 _name: &'static str,
177 events: Vec<EventType>,
178 callback: Weak<dyn Hook>,
179 ) -> HooksRegistration {
180 Self { events, callback }
181 }
182}
183
184#[derive(Clone)]
187pub struct CapabilityReceiver {
188 inner: Arc<StdMutex<Option<Receiver>>>,
189}
190
191impl CapabilityReceiver {
192 pub fn new() -> (Self, Connector) {
195 let (receiver, sender) = Connector::new();
196 let inner = Arc::new(StdMutex::new(Some(receiver)));
197 (Self { inner }, sender)
198 }
199
200 pub fn take(&self) -> Option<Receiver> {
202 self.inner.lock().unwrap().take()
203 }
204
205 pub fn is_taken(&self) -> bool {
207 self.inner.lock().unwrap().is_none()
208 }
209}
210
211#[async_trait]
212impl TransferEvent for CapabilityReceiver {
213 async fn transfer(&self) -> Self {
214 let receiver = self.take();
215 let inner = Arc::new(StdMutex::new(receiver));
216 Self { inner }
217 }
218}
219
220#[derive(Clone)]
221pub enum EventPayload {
222 CapabilityRequested {
224 source_moniker: Moniker,
225 name: String,
226 receiver: CapabilityReceiver,
227 },
228 Destroyed,
229 Resolved {
230 component: WeakInstanceToken,
231 decl: ComponentDecl,
232 },
233 Unresolved,
234 Started {
235 runtime: RuntimeInfo,
236 component_decl: ComponentDecl,
237 },
238 Stopped {
239 status: zx::Status,
240 exit_code: Option<i64>,
241 stop_time: zx::BootInstant,
242 stop_time_monotonic: zx::MonotonicInstant,
243 execution_duration: zx::MonotonicDuration,
244 requested_escrow: bool,
245 },
246 DebugStarted {
247 runtime_dir: Option<fio::DirectoryProxy>,
248 break_on_start: Arc<zx::EventPair>,
249 },
250}
251
252#[derive(Clone)]
254pub struct RuntimeInfo {
255 pub diagnostics_receiver: Arc<Mutex<Option<oneshot::Receiver<fcrunner::ComponentDiagnostics>>>>,
256 pub start_time: zx::BootInstant,
257 pub start_time_monotonic: zx::MonotonicInstant,
258}
259
260impl RuntimeInfo {
261 pub fn new(
262 timestamp: zx::BootInstant,
263 timestamp_monotonic: zx::MonotonicInstant,
264 diagnostics_receiver: oneshot::Receiver<fcrunner::ComponentDiagnostics>,
265 ) -> Self {
266 let diagnostics_receiver = Arc::new(Mutex::new(Some(diagnostics_receiver)));
267 Self {
268 diagnostics_receiver,
269 start_time: timestamp,
270 start_time_monotonic: timestamp_monotonic,
271 }
272 }
273}
274
275impl fmt::Debug for EventPayload {
276 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
277 let mut formatter = fmt.debug_struct("EventPayload");
278 formatter.field("type", &self.event_type());
279 match self {
280 EventPayload::CapabilityRequested { name, .. } => {
281 formatter.field("name", &name).finish()
282 }
283 EventPayload::Started { component_decl, .. } => {
284 formatter.field("component_decl", &component_decl).finish()
285 }
286 EventPayload::Resolved { component: _, decl, .. } => {
287 formatter.field("decl", decl).finish()
288 }
289 EventPayload::Stopped { status, exit_code, .. } => {
290 formatter.field("status", status).field("exit_code", exit_code).finish()
291 }
292 EventPayload::Unresolved
293 | EventPayload::Destroyed
294 | EventPayload::DebugStarted { .. } => formatter.finish(),
295 }
296 }
297}
298
299#[derive(Clone, Debug)]
300pub struct Event {
301 pub target_moniker: ExtendedMoniker,
303
304 pub component_url: Url,
306
307 pub payload: EventPayload,
309
310 pub timestamp: zx::BootInstant,
312}
313
314impl Event {
315 pub fn new_builtin(payload: EventPayload) -> Self {
316 Self {
317 target_moniker: ExtendedMoniker::ComponentManager,
318 component_url: "file:///bin/component_manager".parse().unwrap(),
319 payload,
320 timestamp: zx::BootInstant::get(),
321 }
322 }
323}
324
325#[async_trait]
326impl TransferEvent for EventPayload {
327 async fn transfer(&self) -> Self {
328 match self {
329 EventPayload::CapabilityRequested { source_moniker, name, receiver } => {
330 EventPayload::CapabilityRequested {
331 source_moniker: source_moniker.clone(),
332 name: name.to_string(),
333 receiver: receiver.transfer().await,
334 }
335 }
336 result => result.clone(),
337 }
338 }
339}
340
341impl HasEventType for Event {
342 fn event_type(&self) -> EventType {
343 self.payload.event_type()
344 }
345}
346
347#[async_trait]
348impl TransferEvent for Event {
349 async fn transfer(&self) -> Self {
350 Self {
351 target_moniker: self.target_moniker.clone(),
352 component_url: self.component_url.clone(),
353 payload: self.payload.transfer().await,
354 timestamp: self.timestamp,
355 }
356 }
357}
358
359impl fmt::Display for Event {
360 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361 let payload = match &self.payload {
362 EventPayload::CapabilityRequested { source_moniker, name, .. } => {
363 format!("requested '{}' from '{}'", name, source_moniker)
364 }
365 EventPayload::Stopped { status, .. } => {
366 format!("with status: {}", status)
367 }
368 EventPayload::Destroyed { .. }
369 | EventPayload::Resolved { .. }
370 | EventPayload::DebugStarted { .. }
371 | EventPayload::Started { .. }
372 | EventPayload::Unresolved => "".to_string(),
373 };
374 write!(f, "[{}] '{}' {}", self.event_type(), self.target_moniker, payload)
375 }
376}
377
378pub struct Hooks {
380 hooks_map: Mutex<HashMap<EventType, Vec<Weak<dyn Hook>>>>,
381}
382
383impl Hooks {
384 pub fn new() -> Self {
385 Self { hooks_map: Mutex::new(HashMap::new()) }
386 }
387
388 pub async fn install(&self, hooks: Vec<HooksRegistration>) {
391 let mut hooks_map = self.hooks_map.lock().await;
392 for hook in hooks {
393 for event in hook.events {
394 let existing_hooks = hooks_map.entry(event).or_insert(vec![]);
395 existing_hooks.push(hook.callback.clone());
396 }
397 }
398 }
399
400 pub async fn install_front_for_test(&self, hooks: Vec<HooksRegistration>) {
405 let mut hooks_map = self.hooks_map.lock().await;
406 for hook in hooks {
407 for event in hook.events {
408 let existing_hooks = hooks_map.entry(event).or_insert(vec![]);
409 existing_hooks.insert(0, hook.callback.clone());
410 }
411 }
412 }
413
414 pub async fn dispatch(&self, event: &Event) {
415 let strong_hooks = {
416 let mut hooks_map = self.hooks_map.lock().await;
417 if let Some(hooks) = hooks_map.get_mut(&event.event_type()) {
418 let mut strong_hooks = vec![];
421 hooks.retain(|hook| {
422 if let Some(hook) = hook.upgrade() {
423 strong_hooks.push(hook);
424 true
425 } else {
426 false
427 }
428 });
429 strong_hooks
430 } else {
431 vec![]
432 }
433 };
434 for hook in strong_hooks {
435 if let Err(err) = hook.on(event).await {
436 warn!(err:%, event:%; "Hook produced error for event");
437 }
438 }
439 }
440}
441
442#[cfg(test)]
443mod tests {
444 use super::*;
445
446 #[fuchsia::test]
448 async fn capability_requested_transfer() {
449 let (receiver, _sender) = CapabilityReceiver::new();
450 let event = Event {
451 target_moniker: ExtendedMoniker::ComponentInstance(Moniker::root()),
452 component_url: "fuchsia-pkg://root".parse().unwrap(),
453 payload: EventPayload::CapabilityRequested {
454 source_moniker: Moniker::root(),
455 name: "foo".to_string(),
456 receiver,
457 },
458 timestamp: zx::BootInstant::get(),
459 };
460
461 let transferred_event = event.transfer().await;
463 match transferred_event.payload {
464 EventPayload::CapabilityRequested { receiver, .. } => {
465 assert!(!receiver.is_taken());
466 }
467 _ => panic!("Event type unexpected"),
468 }
469
470 match &event.payload {
472 EventPayload::CapabilityRequested { receiver, .. } => {
473 assert!(receiver.is_taken());
474 }
475 _ => panic!("Event type unexpected"),
476 }
477
478 let second_transferred_event = event.transfer().await;
480 match &second_transferred_event.payload {
481 EventPayload::CapabilityRequested { receiver, .. } => {
482 assert!(receiver.is_taken());
483 }
484 _ => panic!("Event type unexpected"),
485 }
486 }
487}