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