1use anyhow::format_err;
6use async_trait::async_trait;
7use cm_rust::ComponentDecl;
8use cm_types::{Name, Url};
9use errors::ModelError;
10use fuchsia_sync::Mutex;
11use futures::channel::oneshot;
12use log::warn;
13use moniker::{ExtendedMoniker, Moniker};
14use sandbox::{Connector, Receiver, WeakInstanceToken};
15use std::collections::HashMap;
16use std::fmt;
17use std::sync::{Arc, 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(Copy, 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 pub 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::Discovered => unreachable!("This isn't used anymore"),
126 fcomponent::EventType::Destroyed => EventType::Destroyed,
127 fcomponent::EventType::Resolved => EventType::Resolved,
128 fcomponent::EventType::Started => EventType::Started,
129 fcomponent::EventType::Stopped => EventType::Stopped,
130 fcomponent::EventType::DebugStarted => EventType::DebugStarted,
131 fcomponent::EventType::Unresolved => EventType::Unresolved,
132 }
133 }
134}
135
136impl From<EventType> for fcomponent::EventType {
137 fn from(event_type: EventType) -> Self {
138 match event_type {
139 EventType::CapabilityRequested => fcomponent::EventType::CapabilityRequested,
140 EventType::Destroyed => fcomponent::EventType::Destroyed,
141 EventType::Resolved => fcomponent::EventType::Resolved,
142 EventType::Started => fcomponent::EventType::Started,
143 EventType::Stopped => fcomponent::EventType::Stopped,
144 EventType::DebugStarted => fcomponent::EventType::DebugStarted,
145 EventType::Unresolved => fcomponent::EventType::Unresolved,
146 }
147 }
148}
149
150#[async_trait]
159pub trait Hook: Send + Sync {
160 async fn on(self: Arc<Self>, event: &Event) -> Result<(), ModelError>;
161}
162
163#[derive(Clone)]
168pub struct HooksRegistration {
169 events: Vec<EventType>,
170 callback: Weak<dyn Hook>,
171}
172
173impl HooksRegistration {
174 pub fn new(
175 _name: &'static str,
176 events: Vec<EventType>,
177 callback: Weak<dyn Hook>,
178 ) -> HooksRegistration {
179 Self { events, callback }
180 }
181}
182
183#[derive(Clone)]
186pub struct CapabilityReceiver {
187 inner: Arc<Mutex<Option<Receiver>>>,
188}
189
190impl CapabilityReceiver {
191 pub fn new() -> (Self, Connector) {
194 let (receiver, sender) = Connector::new();
195 let inner = Arc::new(Mutex::new(Some(receiver)));
196 (Self { inner }, sender)
197 }
198
199 pub fn take(&self) -> Option<Receiver> {
201 self.inner.lock().take()
202 }
203
204 pub fn is_taken(&self) -> bool {
206 self.inner.lock().is_none()
207 }
208}
209
210#[async_trait]
211impl TransferEvent for CapabilityReceiver {
212 async fn transfer(&self) -> Self {
213 let receiver = self.take();
214 let inner = Arc::new(Mutex::new(receiver));
215 Self { inner }
216 }
217}
218
219#[derive(Clone)]
220pub enum EventPayload {
221 CapabilityRequested {
223 source_moniker: Moniker,
224 name: String,
225 receiver: CapabilityReceiver,
226 },
227 Destroyed,
228 Resolved {
229 component: WeakInstanceToken,
230 decl: Box<ComponentDecl>,
231 },
232 Unresolved,
233 Started {
234 runtime: RuntimeInfo,
235 },
236 Stopped {
237 status: zx::Status,
238 exit_code: Option<i64>,
239 stop_time: zx::BootInstant,
240 stop_time_monotonic: zx::MonotonicInstant,
241 execution_duration: zx::MonotonicDuration,
242 requested_escrow: bool,
243 },
244 DebugStarted {
245 runtime_dir: Option<fio::DirectoryProxy>,
246 break_on_start: Arc<zx::EventPair>,
247 },
248}
249
250#[derive(Clone)]
252pub struct RuntimeInfo {
253 pub diagnostics_receiver: Arc<Mutex<Option<oneshot::Receiver<fcrunner::ComponentDiagnostics>>>>,
254 pub start_time: zx::BootInstant,
255 pub start_time_monotonic: zx::MonotonicInstant,
256}
257
258impl RuntimeInfo {
259 pub fn new(
260 timestamp: zx::BootInstant,
261 timestamp_monotonic: zx::MonotonicInstant,
262 diagnostics_receiver: oneshot::Receiver<fcrunner::ComponentDiagnostics>,
263 ) -> Self {
264 let diagnostics_receiver = Arc::new(Mutex::new(Some(diagnostics_receiver)));
265 Self {
266 diagnostics_receiver,
267 start_time: timestamp,
268 start_time_monotonic: timestamp_monotonic,
269 }
270 }
271}
272
273impl fmt::Debug for EventPayload {
274 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
275 let mut formatter = fmt.debug_struct("EventPayload");
276 formatter.field("type", &self.event_type());
277 match self {
278 EventPayload::CapabilityRequested { name, .. } => {
279 formatter.field("name", &name).finish()
280 }
281 EventPayload::Resolved { component: _, decl, .. } => {
282 formatter.field("decl", &*decl).finish()
283 }
284 EventPayload::Stopped { status, exit_code, .. } => {
285 formatter.field("status", status).field("exit_code", exit_code).finish()
286 }
287 EventPayload::Unresolved
288 | EventPayload::Destroyed
289 | EventPayload::Started { .. }
290 | EventPayload::DebugStarted { .. } => formatter.finish(),
291 }
292 }
293}
294
295#[derive(Clone, Debug)]
296pub struct Event {
297 pub target_moniker: ExtendedMoniker,
299
300 pub component_url: Url,
302
303 pub payload: EventPayload,
305
306 pub timestamp: zx::BootInstant,
308}
309
310impl Event {
311 pub fn new_builtin(payload: EventPayload) -> Self {
312 Self {
313 target_moniker: ExtendedMoniker::ComponentManager,
314 component_url: "file:///bin/component_manager".parse().unwrap(),
315 payload,
316 timestamp: zx::BootInstant::get(),
317 }
318 }
319}
320
321#[async_trait]
322impl TransferEvent for EventPayload {
323 async fn transfer(&self) -> Self {
324 match self {
325 EventPayload::CapabilityRequested { source_moniker, name, receiver } => {
326 EventPayload::CapabilityRequested {
327 source_moniker: source_moniker.clone(),
328 name: name.to_string(),
329 receiver: receiver.transfer().await,
330 }
331 }
332 result => result.clone(),
333 }
334 }
335}
336
337impl HasEventType for Event {
338 fn event_type(&self) -> EventType {
339 self.payload.event_type()
340 }
341}
342
343#[async_trait]
344impl TransferEvent for Event {
345 async fn transfer(&self) -> Self {
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
355impl fmt::Display for Event {
356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357 let payload = match &self.payload {
358 EventPayload::CapabilityRequested { source_moniker, name, .. } => {
359 format!("requested '{}' from '{}'", name, source_moniker)
360 }
361 EventPayload::Stopped { status, .. } => {
362 format!("with status: {}", status)
363 }
364 EventPayload::Destroyed { .. }
365 | EventPayload::Resolved { .. }
366 | EventPayload::DebugStarted { .. }
367 | EventPayload::Started { .. }
368 | EventPayload::Unresolved => "".to_string(),
369 };
370 write!(f, "[{}] '{}' {}", self.event_type(), self.target_moniker, payload)
371 }
372}
373
374pub struct Hooks {
376 hooks_map: Mutex<HashMap<EventType, Vec<Weak<dyn Hook>>>>,
377}
378
379impl Hooks {
380 pub fn new() -> Self {
381 Self { hooks_map: Mutex::new(HashMap::new()) }
382 }
383
384 pub fn install(&self, hooks: Vec<HooksRegistration>) {
387 let mut hooks_map = self.hooks_map.lock();
388 for hook in hooks {
389 for event in hook.events {
390 let existing_hooks = hooks_map.entry(event).or_insert(vec![]);
391 existing_hooks.push(hook.callback.clone());
392 }
393 }
394 }
395
396 pub fn install_front_for_test(&self, hooks: Vec<HooksRegistration>) {
401 let mut hooks_map = self.hooks_map.lock();
402 for hook in hooks {
403 for event in hook.events {
404 let existing_hooks = hooks_map.entry(event).or_insert(vec![]);
405 existing_hooks.insert(0, hook.callback.clone());
406 }
407 }
408 }
409
410 pub async fn dispatch(&self, event: &Event) {
411 let strong_hooks = {
412 let mut hooks_map = self.hooks_map.lock();
413 if let Some(hooks) = hooks_map.get_mut(&event.event_type()) {
414 let mut strong_hooks = vec![];
417 hooks.retain(|hook| {
418 if let Some(hook) = hook.upgrade() {
419 strong_hooks.push(hook);
420 true
421 } else {
422 false
423 }
424 });
425 strong_hooks
426 } else {
427 vec![]
428 }
429 };
430 for hook in strong_hooks {
431 if let Err(err) = hook.on(event).await {
432 warn!(err:%, event:%; "Hook produced error for event");
433 }
434 }
435 }
436}
437
438#[cfg(test)]
439mod tests {
440 use super::*;
441
442 #[fuchsia::test]
444 async fn capability_requested_transfer() {
445 let (receiver, _sender) = CapabilityReceiver::new();
446 let event = Event {
447 target_moniker: ExtendedMoniker::ComponentInstance(Moniker::root()),
448 component_url: "fuchsia-pkg://root".parse().unwrap(),
449 payload: EventPayload::CapabilityRequested {
450 source_moniker: Moniker::root(),
451 name: "foo".to_string(),
452 receiver,
453 },
454 timestamp: zx::BootInstant::get(),
455 };
456
457 let transferred_event = event.transfer().await;
459 match transferred_event.payload {
460 EventPayload::CapabilityRequested { receiver, .. } => {
461 assert!(!receiver.is_taken());
462 }
463 _ => panic!("Event type unexpected"),
464 }
465
466 match &event.payload {
468 EventPayload::CapabilityRequested { receiver, .. } => {
469 assert!(receiver.is_taken());
470 }
471 _ => panic!("Event type unexpected"),
472 }
473
474 let second_transferred_event = event.transfer().await;
476 match &second_transferred_event.payload {
477 EventPayload::CapabilityRequested { receiver, .. } => {
478 assert!(receiver.is_taken());
479 }
480 _ => panic!("Event type unexpected"),
481 }
482 }
483}