1use fidl::Error::ClientChannelClosed;
6use fidl_fuchsia_memory_attribution as fattribution;
7use fuchsia_sync::Mutex;
8use log::error;
9use measure_tape_for_attribution::Measurable;
10use std::collections::HashMap;
11use std::sync::Arc;
12use thiserror::Error;
13
14mod key {
15 #[derive(PartialEq, Eq, Clone, Copy)]
17 pub struct Key(u64);
18
19 pub struct KeyGenerator {
21 next: Key,
22 }
23
24 impl Default for KeyGenerator {
25 fn default() -> Self {
26 Self { next: Key(0) }
27 }
28 }
29
30 impl KeyGenerator {
31 pub fn next(&mut self) -> Key {
33 let next_key = self.next;
34 self.next = Key(self.next.0.checked_add(1).expect("Key generator overflow"));
35 next_key
36 }
37 }
38}
39
40type GetAttributionFn = dyn Fn() -> Vec<fattribution::AttributionUpdate> + Send;
43
44#[derive(Error, Debug)]
46pub enum AttributionServerObservationError {
47 #[error("multiple pending observations for the same Observer")]
48 GetUpdateAlreadyPending,
49}
50
51#[derive(Clone, PartialEq, Eq, Hash)]
52struct PrincipalIdentifier(u64);
53
54#[derive(Clone)]
63pub struct AttributionServerHandle {
64 inner: Arc<Mutex<AttributionServer>>,
65}
66
67impl AttributionServerHandle {
68 pub fn new_observer(&self, control_handle: fattribution::ProviderControlHandle) -> Observer {
72 AttributionServer::register(&self.inner, control_handle)
73 }
74
75 pub fn new_publisher(&self) -> Publisher {
77 Publisher { inner: self.inner.clone() }
78 }
79}
80
81pub struct Observer {
85 inner: Arc<Mutex<AttributionServer>>,
86 subscription_id: key::Key,
87}
88
89impl Observer {
90 pub fn next(&self, responder: fattribution::ProviderGetResponder) {
98 self.inner.lock().next(responder)
99 }
100}
101
102impl Drop for Observer {
103 fn drop(&mut self) {
104 self.inner.lock().unregister(self.subscription_id);
105 }
106}
107
108pub struct Publisher {
110 inner: Arc<Mutex<AttributionServer>>,
111}
112
113impl Publisher {
114 pub fn on_update(&self, updates: Vec<fattribution::AttributionUpdate>) {
118 self.inner.lock().on_update(updates)
121 }
122}
123
124pub struct AttributionServer {
125 state: Box<GetAttributionFn>,
126 consumer: Option<AttributionConsumer>,
127 key_generator: key::KeyGenerator,
128}
129
130impl AttributionServer {
131 pub fn new(state: Box<GetAttributionFn>) -> AttributionServerHandle {
135 AttributionServerHandle {
136 inner: Arc::new(Mutex::new(AttributionServer {
137 state,
138 consumer: None,
139 key_generator: Default::default(),
140 })),
141 }
142 }
143
144 pub fn on_update(&mut self, updates: Vec<fattribution::AttributionUpdate>) {
145 if let Some(consumer) = &mut self.consumer {
146 return consumer.update_and_notify(updates);
147 }
148 }
149
150 pub fn next(&mut self, responder: fattribution::ProviderGetResponder) {
152 let entry = self.consumer.as_mut().unwrap();
153 entry.get_update(responder, self.state.as_ref());
154 }
155
156 pub fn register(
157 inner: &Arc<Mutex<Self>>,
158 control_handle: fattribution::ProviderControlHandle,
159 ) -> Observer {
160 let mut locked_inner = inner.lock();
161
162 if locked_inner.consumer.is_some() {
163 log::warn!("Multiple connection requests to AttributionProvider");
164 }
167
168 let key = locked_inner.key_generator.next();
169
170 locked_inner.consumer = Some(AttributionConsumer::new(control_handle, key.clone()));
171 Observer { inner: inner.clone(), subscription_id: key }
172 }
173
174 pub fn unregister(&mut self, key: key::Key) {
177 if let Some(consumer) = &self.consumer {
178 if consumer.subscription_id == key {
179 self.consumer = None;
180 }
181 }
182 }
183}
184
185#[derive(Default)]
187struct CoalescedUpdate {
188 add: Option<fattribution::AttributionUpdate>,
189 update: Option<fattribution::AttributionUpdate>,
190 remove: Option<fattribution::AttributionUpdate>,
191}
192
193#[derive(PartialEq)]
195enum ShouldKeepUpdate {
196 KEEP,
197 DISCARD,
198}
199
200impl CoalescedUpdate {
201 pub fn update(&mut self, u: fattribution::AttributionUpdate) -> ShouldKeepUpdate {
203 match u {
204 fattribution::AttributionUpdate::Add(u) => {
205 self.add = Some(fattribution::AttributionUpdate::Add(u));
206 self.update = None;
207 self.remove = None;
208 }
209 fattribution::AttributionUpdate::Update(u) => {
210 self.update = Some(fattribution::AttributionUpdate::Update(u));
211 }
212 fattribution::AttributionUpdate::Remove(u) => {
213 if self.add.is_some() {
214 return ShouldKeepUpdate::DISCARD;
216 }
217 self.remove = Some(fattribution::AttributionUpdate::Remove(u));
218 }
219 fattribution::AttributionUpdateUnknown!() => {
220 error!("Unknown attribution update type");
221 }
222 };
223 ShouldKeepUpdate::KEEP
224 }
225
226 pub fn get_updates(self) -> Vec<fattribution::AttributionUpdate> {
227 let mut result = Vec::new();
228 if let Some(u) = self.add {
229 result.push(u);
230 }
231 if let Some(u) = self.update {
232 result.push(u);
233 }
234 if let Some(u) = self.remove {
235 result.push(u);
236 }
237 result
238 }
239
240 pub fn size(&self) -> (usize, usize) {
241 let (mut bytes, mut handles) = (0, 0);
242 if let Some(u) = &self.add {
243 let m = u.measure();
244 bytes += m.num_bytes;
245 handles += m.num_handles;
246 }
247 if let Some(u) = &self.update {
248 let m = u.measure();
249 bytes += m.num_bytes;
250 handles += m.num_handles;
251 }
252 if let Some(u) = &self.remove {
253 let m = u.measure();
254 bytes += m.num_bytes;
255 handles += m.num_handles;
256 }
257 (bytes, handles)
258 }
259}
260
261struct AttributionConsumer {
263 first: bool,
265
266 pending: HashMap<PrincipalIdentifier, CoalescedUpdate>,
268
269 observer_control_handle: fattribution::ProviderControlHandle,
271
272 responder: Option<fattribution::ProviderGetResponder>,
274
275 subscription_id: key::Key,
277}
278
279impl Drop for AttributionConsumer {
280 fn drop(&mut self) {
281 self.observer_control_handle.shutdown_with_epitaph(zx::Status::CANCELED);
282 }
283}
284
285impl AttributionConsumer {
286 pub fn new(
289 observer_control_handle: fattribution::ProviderControlHandle,
290 key: key::Key,
291 ) -> Self {
292 AttributionConsumer {
293 first: true,
294 pending: HashMap::new(),
295 observer_control_handle: observer_control_handle,
296 responder: None,
297 subscription_id: key,
298 }
299 }
300
301 pub fn get_update(
306 &mut self,
307 responder: fattribution::ProviderGetResponder,
308 gen_state: &GetAttributionFn,
309 ) {
310 if self.responder.is_some() {
311 self.observer_control_handle.shutdown_with_epitaph(zx::Status::BAD_STATE);
312 return;
313 }
314 if self.first {
315 self.first = false;
316 self.pending.clear();
317 self.responder = Some(responder);
318 self.update_and_notify(gen_state());
319 return;
320 }
321 self.responder = Some(responder);
322 self.maybe_notify();
323 }
324
325 pub fn update_and_notify(&mut self, updated_state: Vec<fattribution::AttributionUpdate>) {
327 for update in updated_state {
328 let principal: PrincipalIdentifier = match &update {
329 fattribution::AttributionUpdate::Add(added_attribution) => {
330 PrincipalIdentifier(added_attribution.identifier.unwrap())
331 }
332 fattribution::AttributionUpdate::Update(update_attribution) => {
333 PrincipalIdentifier(update_attribution.identifier.unwrap())
334 }
335 fattribution::AttributionUpdate::Remove(remove_attribution) => {
336 PrincipalIdentifier(*remove_attribution)
337 }
338 &fattribution::AttributionUpdateUnknown!() => {
339 unimplemented!()
340 }
341 };
342 if self.pending.entry(principal.clone()).or_insert(Default::default()).update(update)
343 == ShouldKeepUpdate::DISCARD
344 {
345 self.pending.remove(&principal);
346 }
347 }
348 self.maybe_notify();
349 }
350
351 fn maybe_notify(&mut self) {
353 if self.pending.is_empty() {
354 return;
355 }
356
357 match self.responder.take() {
358 Some(observer) => {
359 let mut iterator = self.pending.drain().peekable();
360 let mut current_size: usize = 32;
361 let mut current_handles: usize = 0;
362 let mut update = Vec::new();
363 while let Some((_, next)) = iterator.peek() {
364 let (update_size, update_handles) = next.size();
365
366 if current_size + update_size > zx::sys::ZX_CHANNEL_MAX_MSG_BYTES as usize {
367 break;
368 }
369 if current_handles + update_handles
370 > zx::sys::ZX_CHANNEL_MAX_MSG_HANDLES as usize
371 {
372 break;
373 }
374 current_size += update_size;
375 current_handles += update_handles;
376 update.extend(iterator.next().unwrap().1.get_updates().into_iter());
377 }
378
379 self.pending = iterator.collect();
380 Self::send_update(update, observer)
381 }
382 None => {}
383 }
384 }
385
386 fn send_update(
388 state: Vec<fattribution::AttributionUpdate>,
389 responder: fattribution::ProviderGetResponder,
390 ) {
391 match responder.send(Ok(fattribution::ProviderGetResponse {
392 attributions: Some(state),
393 ..Default::default()
394 })) {
395 Ok(()) => {} Err(e) => {
397 if let ClientChannelClosed { epitaph: fidl::Epitaph::PeerClosed, .. } = e {
399 return;
401 }
402 error!("Failed to send memory state to observer: {}", e);
403 }
404 }
405 }
406}
407
408#[cfg(test)]
409mod tests {
410 use assert_matches::assert_matches;
411
412 use super::*;
413 use fidl::endpoints::RequestStream;
414 use fuchsia_async as fasync;
415 use futures::TryStreamExt;
416
417 #[test]
419 fn test_attribute_memory() {
420 let mut exec = fasync::TestExecutor::new();
421 let server = AttributionServer::new(Box::new(|| {
422 let new_principal = fattribution::NewPrincipal {
423 identifier: Some(0),
424 description: Some(fattribution::Description::Part("part".to_owned())),
425 principal_type: Some(fattribution::PrincipalType::Runnable),
426 detailed_attribution: None,
427 __source_breaking: fidl::marker::SourceBreaking,
428 };
429 vec![fattribution::AttributionUpdate::Add(new_principal)]
430 }));
431 let (snapshot_provider, snapshot_request_stream) =
432 fidl::endpoints::create_proxy_and_stream::<fattribution::ProviderMarker>();
433
434 let observer = server.new_observer(snapshot_request_stream.control_handle());
435 fasync::Task::spawn(async move {
436 serve(observer, snapshot_request_stream).await.unwrap();
437 })
438 .detach();
439
440 let attributions =
441 exec.run_singlethreaded(snapshot_provider.get()).unwrap().unwrap().attributions;
442 assert!(attributions.is_some());
443
444 let attributions_vec = attributions.unwrap();
445 assert_eq!(attributions_vec.len(), 1);
447 let new_attrib = attributions_vec.get(0).unwrap();
448 let fattribution::AttributionUpdate::Add(added_principal) = new_attrib else {
449 panic!("Not a new principal");
450 };
451 assert_eq!(added_principal.identifier, Some(0));
452 assert_eq!(added_principal.principal_type, Some(fattribution::PrincipalType::Runnable));
453
454 server.new_publisher().on_update(vec![fattribution::AttributionUpdate::Update(
455 fattribution::UpdatedPrincipal { identifier: Some(0), ..Default::default() },
456 )]);
457 let attributions =
458 exec.run_singlethreaded(snapshot_provider.get()).unwrap().unwrap().attributions;
459 assert!(attributions.is_some());
460
461 let attributions_vec = attributions.unwrap();
462 assert_eq!(attributions_vec.len(), 1);
464 let updated_attrib = attributions_vec.get(0).unwrap();
465 let fattribution::AttributionUpdate::Update(updated_principal) = updated_attrib else {
466 panic!("Not an updated principal");
467 };
468 assert_eq!(updated_principal.identifier, Some(0));
469 }
470
471 pub async fn serve(
472 observer: Observer,
473 mut stream: fattribution::ProviderRequestStream,
474 ) -> Result<(), fidl::Error> {
475 while let Some(request) = stream.try_next().await? {
476 match request {
477 fattribution::ProviderRequest::Get { responder } => {
478 observer.next(responder);
479 }
480 fattribution::ProviderRequest::_UnknownMethod { .. } => {
481 assert!(false);
482 }
483 }
484 }
485 Ok(())
486 }
487
488 #[test]
490 fn test_disconnect_on_new_connection() {
491 let mut exec = fasync::TestExecutor::new();
492 let server = AttributionServer::new(Box::new(|| {
493 vec![fattribution::AttributionUpdate::Add(fattribution::NewPrincipal {
494 identifier: Some(1),
495 description: Some(fattribution::Description::Part("part1".to_owned())),
496 principal_type: Some(fattribution::PrincipalType::Runnable),
497 detailed_attribution: None,
498 ..Default::default()
499 })]
500 }));
501 let (snapshot_provider, snapshot_request_stream) =
502 fidl::endpoints::create_proxy_and_stream::<fattribution::ProviderMarker>();
503
504 let observer = server.new_observer(snapshot_request_stream.control_handle());
505
506 let (new_snapshot_provider, new_snapshot_request_stream) =
507 fidl::endpoints::create_proxy_and_stream::<fattribution::ProviderMarker>();
508
509 let new_observer = server.new_observer(new_snapshot_request_stream.control_handle());
510 fasync::Task::spawn(async move {
511 serve(new_observer, new_snapshot_request_stream).await.unwrap();
512 })
513 .detach();
514
515 drop(observer);
516 let result = exec.run_singlethreaded(snapshot_provider.get());
517 assert_matches!(
518 result,
519 Err(ClientChannelClosed { epitaph, .. }) if epitaph == zx::Status::CANCELED
520 );
521
522 let result = exec.run_singlethreaded(new_snapshot_provider.get());
523 assert!(result.is_ok());
524 server.new_publisher().on_update(vec![fattribution::AttributionUpdate::Add(
525 fattribution::NewPrincipal {
526 identifier: Some(2),
527 description: Some(fattribution::Description::Part("part2".to_owned())),
528 principal_type: Some(fattribution::PrincipalType::Runnable),
529 detailed_attribution: None,
530 ..Default::default()
531 },
532 )]);
533 let result = exec.run_singlethreaded(new_snapshot_provider.get());
534 assert!(result.is_ok());
535 }
536
537 #[test]
540 fn test_disconnect_on_two_pending_gets() {
541 let mut exec = fasync::TestExecutor::new();
542 let server = AttributionServer::new(Box::new(|| {
543 let new_principal = fattribution::NewPrincipal {
544 identifier: Some(0),
545 principal_type: Some(fattribution::PrincipalType::Runnable),
546 ..Default::default()
547 };
548 vec![fattribution::AttributionUpdate::Add(new_principal)]
549 }));
550 let (snapshot_provider, snapshot_request_stream) =
551 fidl::endpoints::create_proxy_and_stream::<fattribution::ProviderMarker>();
552
553 let observer = server.new_observer(snapshot_request_stream.control_handle());
554 fasync::Task::spawn(async move {
555 serve(observer, snapshot_request_stream).await.unwrap();
556 })
557 .detach();
558
559 exec.run_singlethreaded(snapshot_provider.get())
561 .expect("Connection dropped")
562 .expect("Get call failed");
563
564 let mut future = snapshot_provider.get();
566
567 let _ = exec.run_until_stalled(&mut future);
568
569 let result = exec.run_singlethreaded(snapshot_provider.get());
571
572 let result2 = exec.run_singlethreaded(future);
573
574 assert_matches!(
575 result2,
576 Err(ClientChannelClosed { epitaph, .. }) if epitaph == zx::Status::BAD_STATE
577 );
578 assert_matches!(
579 result,
580 Err(ClientChannelClosed { epitaph, .. }) if epitaph == zx::Status::BAD_STATE
581 );
582 }
583
584 #[test]
586 fn test_no_update_on_first_call() {
587 let mut exec = fasync::TestExecutor::new();
588 let server = AttributionServer::new(Box::new(|| {
589 let new_principal = fattribution::NewPrincipal {
590 identifier: Some(0),
591 principal_type: Some(fattribution::PrincipalType::Runnable),
592 ..Default::default()
593 };
594 vec![fattribution::AttributionUpdate::Add(new_principal)]
595 }));
596 let (snapshot_provider, snapshot_request_stream) =
597 fidl::endpoints::create_proxy_and_stream::<fattribution::ProviderMarker>();
598
599 let observer = server.new_observer(snapshot_request_stream.control_handle());
600 fasync::Task::spawn(async move {
601 serve(observer, snapshot_request_stream).await.unwrap();
602 })
603 .detach();
604
605 server.new_publisher().on_update(vec![fattribution::AttributionUpdate::Update(
606 fattribution::UpdatedPrincipal { identifier: Some(0), ..Default::default() },
607 )]);
608
609 let attributions =
611 exec.run_singlethreaded(snapshot_provider.get()).unwrap().unwrap().attributions;
612 assert!(attributions.is_some());
613
614 let attributions_vec = attributions.unwrap();
615 assert_eq!(attributions_vec.len(), 1);
617 let new_attrib = attributions_vec.get(0).unwrap();
618 let fattribution::AttributionUpdate::Add(added_principal) = new_attrib else {
619 panic!("Not a new principal");
620 };
621 assert_eq!(added_principal.identifier, Some(0));
622 assert_eq!(added_principal.principal_type, Some(fattribution::PrincipalType::Runnable));
623 }
624}