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 runtime_capabilities::{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
26pub trait TransferEvent: Send + Sync {
29 fn transfer(&self) -> impl std::future::Future<Output = Self> + Send;
30}
31
32#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
33pub enum EventType {
34 CapabilityRequested,
37 Destroyed,
40 Resolved,
42 Started,
44 Stopped,
47 DebugStarted,
50 Unresolved,
52}
53
54impl EventType {
55 pub fn as_str(&self) -> &str {
56 match self {
57 EventType::CapabilityRequested => "capability_requested",
58 EventType::Destroyed => "destroyed",
59 EventType::Resolved => "resolved",
60 EventType::Started => "started",
61 EventType::Stopped => "stopped",
62 EventType::DebugStarted => "debug_started",
63 EventType::Unresolved => "unresolved",
64 }
65 }
66
67 pub fn values() -> Vec<EventType> {
69 vec![
70 EventType::CapabilityRequested,
71 EventType::Destroyed,
72 EventType::Resolved,
73 EventType::Started,
74 EventType::Stopped,
75 EventType::DebugStarted,
76 EventType::Unresolved,
77 ]
78 }
79}
80
81impl From<EventType> for Name {
82 fn from(event_type: EventType) -> Name {
83 event_type.as_str().parse().unwrap()
84 }
85}
86
87impl fmt::Display for EventType {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 write!(f, "{}", self.as_str())
90 }
91}
92
93impl TryFrom<String> for EventType {
94 type Error = anyhow::Error;
95 fn try_from(string: String) -> Result<EventType, Self::Error> {
96 for value in EventType::values() {
97 if value.as_str() == string {
98 return Ok(value);
99 }
100 }
101 Err(format_err!("invalid string for event type: {:?}", string))
102 }
103}
104
105impl HasEventType for EventPayload {
106 fn event_type(&self) -> EventType {
107 match self {
108 EventPayload::CapabilityRequested { .. } => EventType::CapabilityRequested,
109 EventPayload::Destroyed => EventType::Destroyed,
110 EventPayload::Resolved { .. } => EventType::Resolved,
111 EventPayload::Started { .. } => EventType::Started,
112 EventPayload::Stopped { .. } => EventType::Stopped,
113 EventPayload::DebugStarted { .. } => EventType::DebugStarted,
114 EventPayload::Unresolved => EventType::Unresolved,
115 }
116 }
117}
118
119impl From<fcomponent::EventType> for EventType {
120 fn from(fidl_event_type: fcomponent::EventType) -> Self {
121 match fidl_event_type {
122 fcomponent::EventType::CapabilityRequested => EventType::CapabilityRequested,
123 fcomponent::EventType::Discovered => unreachable!("This isn't used anymore"),
124 fcomponent::EventType::Destroyed => EventType::Destroyed,
125 fcomponent::EventType::Resolved => EventType::Resolved,
126 fcomponent::EventType::Started => EventType::Started,
127 fcomponent::EventType::Stopped => EventType::Stopped,
128 fcomponent::EventType::DebugStarted => EventType::DebugStarted,
129 fcomponent::EventType::Unresolved => EventType::Unresolved,
130 }
131 }
132}
133
134impl From<EventType> for fcomponent::EventType {
135 fn from(event_type: EventType) -> Self {
136 match event_type {
137 EventType::CapabilityRequested => fcomponent::EventType::CapabilityRequested,
138 EventType::Destroyed => fcomponent::EventType::Destroyed,
139 EventType::Resolved => fcomponent::EventType::Resolved,
140 EventType::Started => fcomponent::EventType::Started,
141 EventType::Stopped => fcomponent::EventType::Stopped,
142 EventType::DebugStarted => fcomponent::EventType::DebugStarted,
143 EventType::Unresolved => fcomponent::EventType::Unresolved,
144 }
145 }
146}
147
148#[async_trait]
157pub trait Hook: Send + Sync {
158 async fn on(self: Arc<Self>, event: &Event) -> Result<(), ModelError>;
159}
160
161#[derive(Clone)]
166pub struct HooksRegistration {
167 events: Vec<EventType>,
168 callback: Weak<dyn Hook>,
169}
170
171impl HooksRegistration {
172 pub fn new(
173 _name: &'static str,
174 events: Vec<EventType>,
175 callback: Weak<dyn Hook>,
176 ) -> HooksRegistration {
177 Self { events, callback }
178 }
179}
180
181#[derive(Clone)]
184pub struct CapabilityReceiver {
185 inner: Arc<Mutex<Option<Receiver>>>,
186}
187
188impl CapabilityReceiver {
189 pub fn new() -> (Self, Connector) {
192 let (receiver, sender) = Connector::new();
193 let inner = Arc::new(Mutex::new(Some(receiver)));
194 (Self { inner }, sender)
195 }
196
197 pub fn take(&self) -> Option<Receiver> {
199 self.inner.lock().take()
200 }
201
202 pub fn is_taken(&self) -> bool {
204 self.inner.lock().is_none()
205 }
206}
207
208impl TransferEvent for CapabilityReceiver {
209 fn transfer(&self) -> impl std::future::Future<Output = Self> + Send {
210 async move {
211 let receiver = self.take();
212 let inner = Arc::new(Mutex::new(receiver));
213 Self { inner }
214 }
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: Box<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
320impl TransferEvent for EventPayload {
321 fn transfer(&self) -> impl std::future::Future<Output = Self> + Send {
322 async move {
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}
336
337impl HasEventType for Event {
338 fn event_type(&self) -> EventType {
339 self.payload.event_type()
340 }
341}
342
343impl TransferEvent for Event {
344 fn transfer(&self) -> impl std::future::Future<Output = Self> + Send {
345 async move {
346 Self {
347 target_moniker: self.target_moniker.clone(),
348 component_url: self.component_url.clone(),
349 payload: self.payload.transfer().await,
350 timestamp: self.timestamp,
351 }
352 }
353 }
354}
355
356impl fmt::Display for Event {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 let payload = match &self.payload {
359 EventPayload::CapabilityRequested { source_moniker, name, .. } => {
360 format!("requested '{}' from '{}'", name, source_moniker)
361 }
362 EventPayload::Stopped { status, .. } => {
363 format!("with status: {}", status)
364 }
365 EventPayload::Destroyed { .. }
366 | EventPayload::Resolved { .. }
367 | EventPayload::DebugStarted { .. }
368 | EventPayload::Started { .. }
369 | EventPayload::Unresolved => "".to_string(),
370 };
371 write!(f, "[{}] '{}' {}", self.event_type(), self.target_moniker, payload)
372 }
373}
374
375pub struct Hooks {
377 hooks_map: Mutex<HashMap<EventType, Vec<Weak<dyn Hook>>>>,
378}
379
380impl Hooks {
381 pub fn new() -> Self {
382 Self { hooks_map: Mutex::new(HashMap::new()) }
383 }
384
385 pub fn install(&self, hooks: Vec<HooksRegistration>) {
388 let mut hooks_map = self.hooks_map.lock();
389 for hook in hooks {
390 for event in hook.events {
391 let existing_hooks = hooks_map.entry(event).or_insert(vec![]);
392 existing_hooks.push(hook.callback.clone());
393 }
394 }
395 }
396
397 pub fn install_front_for_test(&self, hooks: Vec<HooksRegistration>) {
402 let mut hooks_map = self.hooks_map.lock();
403 for hook in hooks {
404 for event in hook.events {
405 let existing_hooks = hooks_map.entry(event).or_insert(vec![]);
406 existing_hooks.insert(0, hook.callback.clone());
407 }
408 }
409 }
410
411 pub async fn dispatch(&self, event: &Event) {
412 let strong_hooks = {
413 let mut hooks_map = self.hooks_map.lock();
414 if let Some(hooks) = hooks_map.get_mut(&event.event_type()) {
415 let mut strong_hooks = vec![];
418 hooks.retain(|hook| {
419 if let Some(hook) = hook.upgrade() {
420 strong_hooks.push(hook);
421 true
422 } else {
423 false
424 }
425 });
426 strong_hooks
427 } else {
428 vec![]
429 }
430 };
431 for hook in strong_hooks {
432 if let Err(err) = hook.on(event).await {
433 warn!(err:%, event:%; "Hook produced error for event");
434 }
435 }
436 }
437}
438
439#[cfg(test)]
440mod tests {
441 use super::*;
442
443 #[fuchsia::test]
445 async fn capability_requested_transfer() {
446 let (receiver, _sender) = CapabilityReceiver::new();
447 let event = Event {
448 target_moniker: ExtendedMoniker::ComponentInstance(Moniker::root()),
449 component_url: "fuchsia-pkg://root".parse().unwrap(),
450 payload: EventPayload::CapabilityRequested {
451 source_moniker: Moniker::root(),
452 name: "foo".to_string(),
453 receiver,
454 },
455 timestamp: zx::BootInstant::get(),
456 };
457
458 let transferred_event = event.transfer().await;
460 match transferred_event.payload {
461 EventPayload::CapabilityRequested { receiver, .. } => {
462 assert!(!receiver.is_taken());
463 }
464 _ => panic!("Event type unexpected"),
465 }
466
467 match &event.payload {
469 EventPayload::CapabilityRequested { receiver, .. } => {
470 assert!(receiver.is_taken());
471 }
472 _ => panic!("Event type unexpected"),
473 }
474
475 let second_transferred_event = event.transfer().await;
477 match &second_transferred_event.payload {
478 EventPayload::CapabilityRequested { receiver, .. } => {
479 assert!(receiver.is_taken());
480 }
481 _ => panic!("Event type unexpected"),
482 }
483 }
484}