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