1use crate::dict::Key;
6use crate::fidl::{IntoFsandboxCapability, registry};
7use crate::{Capability, Connector, Dict, DirConnector, Message, WeakInstanceToken};
8use cm_types::RelativePath;
9use fidl::AsHandleRef;
10use fidl::handle::Signals;
11use futures::{FutureExt, TryStreamExt};
12use log::warn;
13use std::collections::HashMap;
14use std::collections::hash_map::Entry;
15use std::sync::{self, Arc, Weak};
16use {fidl_fuchsia_component_sandbox as fsandbox, fuchsia_async as fasync};
17
18type Store = sync::Mutex<HashMap<u64, Capability>>;
19
20pub async fn serve_capability_store(
21 mut stream: fsandbox::CapabilityStoreRequestStream,
22 receiver_scope: &fasync::Scope,
30 token: WeakInstanceToken,
31) -> Result<(), fidl::Error> {
32 let outer_store: Arc<Store> = Arc::new(Store::new(Default::default()));
33 while let Some(request) = stream.try_next().await? {
34 let mut store = outer_store.lock().unwrap();
35 match request {
36 fsandbox::CapabilityStoreRequest::Duplicate { id, dest_id, responder } => {
37 let result = (|| {
38 let cap = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
39 let cap = cap
40 .try_clone()
41 .map_err(|_| fsandbox::CapabilityStoreError::NotDuplicatable)?;
42 insert_capability(&mut store, dest_id, cap)
43 })();
44 responder.send(result)?;
45 }
46 fsandbox::CapabilityStoreRequest::Drop { id, responder } => {
47 let result =
48 store.remove(&id).map(|_| ()).ok_or(fsandbox::CapabilityStoreError::IdNotFound);
49 responder.send(result)?;
50 }
51 fsandbox::CapabilityStoreRequest::Export { id, responder } => {
52 let result = (|| {
53 let cap =
54 store.remove(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
55 Ok(cap.into_fsandbox_capability(token.clone()))
56 })();
57 responder.send(result)?;
58 }
59 fsandbox::CapabilityStoreRequest::Import { id, capability, responder } => {
60 let result = (|| {
61 let capability = capability
62 .try_into()
63 .map_err(|_| fsandbox::CapabilityStoreError::BadCapability)?;
64 insert_capability(&mut store, id, capability)
65 })();
66 responder.send(result)?;
67 }
68 fsandbox::CapabilityStoreRequest::ConnectorCreate { id, receiver, responder } => {
69 let result = (|| {
70 let connector = Connector::new_with_fidl_receiver(receiver, receiver_scope);
71 insert_capability(&mut store, id, Capability::Connector(connector))
72 })();
73 responder.send(result)?;
74 }
75 fsandbox::CapabilityStoreRequest::ConnectorOpen { id, server_end, responder } => {
76 let result = (|| {
77 let this = get_connector(&store, id)?;
78 let _ = this.send(Message { channel: server_end });
79 Ok(())
80 })();
81 responder.send(result)?;
82 }
83 fsandbox::CapabilityStoreRequest::DirConnectorCreate { id, receiver, responder } => {
84 let result = (|| {
85 let connector = DirConnector::new_with_fidl_receiver(receiver, receiver_scope);
86 insert_capability(&mut store, id, Capability::DirConnector(connector))
87 })();
88 responder.send(result)?;
89 }
90 fsandbox::CapabilityStoreRequest::DirConnectorOpen { payload, responder } => {
91 let result = (|| {
92 let Some(id) = payload.id else {
93 return Err(fsandbox::CapabilityStoreError::InvalidArgs);
94 };
95 let Some(server_end) = payload.server_end else {
96 return Err(fsandbox::CapabilityStoreError::InvalidArgs);
97 };
98 let this = get_dir_connector(&store, id)?;
99 let path = payload
100 .path
101 .map(RelativePath::new)
102 .transpose()
103 .map_err(|_| fsandbox::CapabilityStoreError::InvalidArgs)?
104 .unwrap_or_else(|| RelativePath::dot());
105 let _ = this.send(server_end, path, payload.flags);
106 Ok(())
107 })();
108 responder.send(result)?;
109 }
110 fsandbox::CapabilityStoreRequest::DictionaryCreate { id, responder } => {
111 let result = insert_capability(&mut store, id, Capability::Dictionary(Dict::new()));
112 responder.send(result)?;
113 }
114 fsandbox::CapabilityStoreRequest::DictionaryLegacyImport {
115 id,
116 client_end,
117 responder,
118 } => {
119 let result = (|| {
120 let capability = Dict::try_from(client_end)
121 .map_err(|_| fsandbox::CapabilityStoreError::BadCapability)?
122 .into();
123 insert_capability(&mut store, id, capability)
124 })();
125 responder.send(result)?;
126 }
127 fsandbox::CapabilityStoreRequest::DictionaryLegacyExport {
128 id,
129 server_end,
130 responder,
131 } => {
132 let result = (|| {
133 let cap =
134 store.remove(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
135 let Capability::Dictionary(_) = &cap else {
136 return Err(fsandbox::CapabilityStoreError::WrongType);
137 };
138 let koid = server_end.basic_info().unwrap().related_koid;
139 registry::insert(
140 cap,
141 koid,
142 fasync::OnSignals::new(server_end, Signals::OBJECT_PEER_CLOSED).map(|_| ()),
143 );
144 Ok(())
145 })();
146 responder.send(result)?
147 }
148 fsandbox::CapabilityStoreRequest::DictionaryInsert { id, item, responder } => {
149 let result = (|| {
150 let this = get_dictionary(&store, id)?;
151 let this = this.clone();
152 let key =
153 item.key.parse().map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
154 let value = store
155 .remove(&item.value)
156 .ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
157 this.insert(key, value)
158 })();
159 responder.send(result)?;
160 }
161 fsandbox::CapabilityStoreRequest::DictionaryGet { id, key, dest_id, responder } => {
162 let result = (|| {
163 let this = get_dictionary(&store, id)?;
164 let key =
165 Key::new(key).map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
166 let cap = match this.get(&key) {
167 Ok(Some(cap)) => Ok(cap),
168 Ok(None) => {
169 this.not_found(key.as_str());
170 Err(fsandbox::CapabilityStoreError::ItemNotFound)
171 }
172 Err(()) => Err(fsandbox::CapabilityStoreError::NotDuplicatable),
173 }?;
174 insert_capability(&mut store, dest_id, cap)
175 })();
176 responder.send(result)?;
177 }
178 fsandbox::CapabilityStoreRequest::DictionaryRemove { id, key, dest_id, responder } => {
179 let result = (|| {
180 let this = get_dictionary(&store, id)?;
181 let key =
182 Key::new(key).map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
183 if let Some(dest_id) = dest_id.as_ref() {
185 if store.contains_key(&dest_id.id) {
186 return Err(fsandbox::CapabilityStoreError::IdAlreadyExists);
187 }
188 }
189 let cap = match this.remove(&key) {
190 Some(cap) => Ok(cap.into()),
191 None => {
192 this.not_found(key.as_str());
193 Err(fsandbox::CapabilityStoreError::ItemNotFound)
194 }
195 }?;
196 if let Some(dest_id) = dest_id.as_ref() {
197 store.insert(dest_id.id, cap);
198 }
199 Ok(())
200 })();
201 responder.send(result)?;
202 }
203 fsandbox::CapabilityStoreRequest::DictionaryCopy { id, dest_id, responder } => {
204 let result = (|| {
205 let this = get_dictionary(&store, id)?;
206 let dict = this
207 .shallow_copy()
208 .map_err(|_| fsandbox::CapabilityStoreError::NotDuplicatable)?;
209 insert_capability(&mut store, dest_id, Capability::Dictionary(dict))
210 })();
211 responder.send(result)?
212 }
213 fsandbox::CapabilityStoreRequest::DictionaryKeys {
214 id,
215 iterator: server_end,
216 responder,
217 } => {
218 let result = (|| {
219 let this = get_dictionary(&store, id)?;
220 let keys = this.keys();
221 let stream = server_end.into_stream();
222 let mut this = this.lock();
223 this.tasks().spawn(serve_dictionary_keys_iterator(keys, stream));
224 Ok(())
225 })();
226 responder.send(result)?
227 }
228 fsandbox::CapabilityStoreRequest::DictionaryEnumerate {
229 id,
230 iterator: server_end,
231 responder,
232 } => {
233 let result = (|| {
234 let this = get_dictionary(&store, id)?;
235 let items = this.enumerate();
236 let stream = server_end.into_stream();
237 let mut this = this.lock();
238 this.tasks().spawn(serve_dictionary_enumerate_iterator(
239 Arc::downgrade(&outer_store),
240 items,
241 stream,
242 ));
243 Ok(())
244 })();
245 responder.send(result)?
246 }
247 fsandbox::CapabilityStoreRequest::DictionaryDrain {
248 id,
249 iterator: server_end,
250 responder,
251 } => {
252 let result = (|| {
253 let this = get_dictionary(&store, id)?;
254 let items = this.drain();
257 if let Some(server_end) = server_end {
258 let stream = server_end.into_stream();
259 let mut this = this.lock();
260 this.tasks().spawn(serve_dictionary_drain_iterator(
261 Arc::downgrade(&outer_store),
262 items,
263 stream,
264 ));
265 }
266 Ok(())
267 })();
268 responder.send(result)?
269 }
270 fsandbox::CapabilityStoreRequest::_UnknownMethod { ordinal, .. } => {
271 warn!("Received unknown CapabilityStore request with ordinal {ordinal}");
272 }
273 }
274 }
275 Ok(())
276}
277
278async fn serve_dictionary_keys_iterator(
279 mut keys: impl Iterator<Item = Key>,
280 mut stream: fsandbox::DictionaryKeysIteratorRequestStream,
281) {
282 while let Ok(Some(request)) = stream.try_next().await {
283 match request {
284 fsandbox::DictionaryKeysIteratorRequest::GetNext { responder } => {
285 let mut chunk = vec![];
286 for _ in 0..fsandbox::MAX_DICTIONARY_ITERATOR_CHUNK {
287 match keys.next() {
288 Some(key) => {
289 chunk.push(key.into());
290 }
291 None => break,
292 }
293 }
294 let _ = responder.send(&chunk);
295 }
296 fsandbox::DictionaryKeysIteratorRequest::_UnknownMethod { ordinal, .. } => {
297 warn!(ordinal:%; "Unknown DictionaryKeysIterator request");
298 }
299 }
300 }
301}
302
303async fn serve_dictionary_enumerate_iterator(
304 store: Weak<Store>,
305 mut items: impl Iterator<Item = (Key, Result<Capability, ()>)>,
306 mut stream: fsandbox::DictionaryEnumerateIteratorRequestStream,
307) {
308 while let Ok(Some(request)) = stream.try_next().await {
309 let Some(store) = store.upgrade() else {
310 return;
311 };
312 let mut store = store.lock().unwrap();
313 match request {
314 fsandbox::DictionaryEnumerateIteratorRequest::GetNext {
315 start_id,
316 limit,
317 responder,
318 } => {
319 let result = (|| {
320 let mut next_id = start_id;
321 let chunk = get_next_chunk(&*store, &mut items, &mut next_id, limit)?;
322 let end_id = next_id;
323
324 let chunk: Vec<_> = chunk
325 .into_iter()
326 .map(|(key, value)| {
327 if let Some((capability, id)) = value {
328 store.insert(id, capability);
329 fsandbox::DictionaryOptionalItem {
330 key: key.into(),
331 value: Some(Box::new(fsandbox::WrappedCapabilityId { id })),
332 }
333 } else {
334 fsandbox::DictionaryOptionalItem { key: key.into(), value: None }
335 }
336 })
337 .collect();
338 Ok((chunk, end_id))
339 })();
340 let err = result.is_err();
341 let _ = responder.send(result);
342 if err {
343 return;
344 }
345 }
346 fsandbox::DictionaryEnumerateIteratorRequest::_UnknownMethod { ordinal, .. } => {
347 warn!(ordinal:%; "Unknown DictionaryEnumerateIterator request");
348 }
349 }
350 }
351}
352
353async fn serve_dictionary_drain_iterator(
354 store: Weak<Store>,
355 items: impl Iterator<Item = (Key, Capability)>,
356 mut stream: fsandbox::DictionaryDrainIteratorRequestStream,
357) {
358 let mut items = items.map(|(key, capability)| (key, Ok(capability)));
360 while let Ok(Some(request)) = stream.try_next().await {
361 let Some(store) = store.upgrade() else {
362 return;
363 };
364 let mut store = store.lock().unwrap();
365 match request {
366 fsandbox::DictionaryDrainIteratorRequest::GetNext { start_id, limit, responder } => {
367 let result = (|| {
368 let mut next_id = start_id;
369 let chunk = get_next_chunk(&*store, &mut items, &mut next_id, limit)?;
370 let end_id = next_id;
371
372 let chunk: Vec<_> = chunk
373 .into_iter()
374 .map(|(key, value)| {
375 let value = value.expect("unreachable: all values are present");
376 let (capability, id) = value;
377 store.insert(id, capability);
378 fsandbox::DictionaryItem { key: key.into(), value: id }
379 })
380 .collect();
381 Ok((chunk, end_id))
382 })();
383 match result {
384 Ok((chunk, id)) => {
385 let _ = responder.send(Ok((&chunk[..], id)));
386 }
387 Err(e) => {
388 let _ = responder.send(Err(e));
389 return;
390 }
391 }
392 }
393 fsandbox::DictionaryDrainIteratorRequest::_UnknownMethod { ordinal, .. } => {
394 warn!(ordinal:%; "Unknown DictionaryDrainIterator request");
395 }
396 }
397 }
398}
399
400fn get_next_chunk(
401 store: &HashMap<u64, Capability>,
402 items: &mut impl Iterator<Item = (Key, Result<Capability, ()>)>,
403 next_id: &mut u64,
404 limit: u32,
405) -> Result<Vec<(Key, Option<(Capability, fsandbox::CapabilityId)>)>, fsandbox::CapabilityStoreError>
406{
407 if limit == 0 || limit > fsandbox::MAX_DICTIONARY_ITERATOR_CHUNK {
408 return Err(fsandbox::CapabilityStoreError::InvalidArgs);
409 }
410
411 let mut chunk = vec![];
412 for _ in 0..limit {
413 match items.next() {
414 Some((key, value)) => {
415 let value = match value {
416 Ok(value) => {
417 let id = *next_id;
418 if store.contains_key(&id) {
421 return Err(fsandbox::CapabilityStoreError::IdAlreadyExists);
422 }
423 *next_id += 1;
424 Some((value, id))
425 }
426 Err(_) => None,
427 };
428 chunk.push((key, value));
429 }
430 None => break,
431 }
432 }
433 Ok(chunk)
434}
435
436fn get_connector(
437 store: &HashMap<u64, Capability>,
438 id: u64,
439) -> Result<&Connector, fsandbox::CapabilityStoreError> {
440 let conn = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
441 if let Capability::Connector(conn) = conn {
442 Ok(conn)
443 } else {
444 Err(fsandbox::CapabilityStoreError::WrongType)
445 }
446}
447
448fn get_dir_connector(
449 store: &HashMap<u64, Capability>,
450 id: u64,
451) -> Result<&DirConnector, fsandbox::CapabilityStoreError> {
452 let conn = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
453 if let Capability::DirConnector(conn) = conn {
454 Ok(conn)
455 } else {
456 Err(fsandbox::CapabilityStoreError::WrongType)
457 }
458}
459
460fn get_dictionary(
461 store: &HashMap<u64, Capability>,
462 id: u64,
463) -> Result<&Dict, fsandbox::CapabilityStoreError> {
464 let dict = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
465 if let Capability::Dictionary(dict) = dict {
466 Ok(dict)
467 } else {
468 Err(fsandbox::CapabilityStoreError::WrongType)
469 }
470}
471
472fn insert_capability(
473 store: &mut HashMap<u64, Capability>,
474 id: u64,
475 cap: Capability,
476) -> Result<(), fsandbox::CapabilityStoreError> {
477 match store.entry(id) {
478 Entry::Occupied(_) => Err(fsandbox::CapabilityStoreError::IdAlreadyExists),
479 Entry::Vacant(entry) => {
480 entry.insert(cap);
481 Ok(())
482 }
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489 use crate::Data;
490 use assert_matches::assert_matches;
491 use fidl::{HandleBased, endpoints};
492
493 #[fuchsia::test]
494 async fn import_export() {
495 let (store, stream) =
496 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
497 let _server = fasync::Task::spawn(async move {
498 let receiver_scope = fasync::Scope::new();
499 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
500 });
501
502 let (ch, _) = fidl::Channel::create();
503 let handle = ch.into_handle();
504 let handle_koid = handle.get_koid().unwrap();
505 let cap1 = Capability::Handle(handle.into());
506 let cap2 = Capability::Data(Data::Int64(42));
507 store
508 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
509 .await
510 .unwrap()
511 .unwrap();
512 store
513 .import(2, cap2.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
514 .await
515 .unwrap()
516 .unwrap();
517
518 let cap1 = store.export(1).await.unwrap().unwrap();
519 let cap2 = store.export(2).await.unwrap().unwrap();
520 assert_matches!(
521 cap1,
522 fsandbox::Capability::Handle(h) if h.get_koid().unwrap() == handle_koid
523 );
524 assert_matches!(
525 cap2,
526 fsandbox::Capability::Data(fsandbox::Data::Int64(i)) if i == 42
527 );
528 }
529
530 #[fuchsia::test]
531 async fn import_error() {
532 let (store, stream) =
533 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
534 let _server = fasync::Task::spawn(async move {
535 let receiver_scope = fasync::Scope::new();
536 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
537 });
538
539 let cap1 = Capability::Data(Data::Int64(42));
540 store
541 .import(
542 1,
543 cap1.try_clone()
544 .unwrap()
545 .into_fsandbox_capability(WeakInstanceToken::new_invalid()),
546 )
547 .await
548 .unwrap()
549 .unwrap();
550 assert_matches!(
551 store
552 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
553 .await
554 .unwrap(),
555 Err(fsandbox::CapabilityStoreError::IdAlreadyExists)
556 );
557
558 let (token, _) = fidl::EventPair::create();
559 let bad_connector = fsandbox::Capability::Connector(fsandbox::Connector { token });
560 assert_matches!(
561 store.import(2, bad_connector).await.unwrap(),
562 Err(fsandbox::CapabilityStoreError::BadCapability)
563 );
564 }
565
566 #[fuchsia::test]
567 async fn export_error() {
568 let (store, stream) =
569 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
570 let _server = fasync::Task::spawn(async move {
571 let receiver_scope = fasync::Scope::new();
572 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
573 });
574
575 let cap1 = Capability::Data(Data::Int64(42));
576 store
577 .import(
578 1,
579 cap1.try_clone()
580 .unwrap()
581 .into_fsandbox_capability(WeakInstanceToken::new_invalid()),
582 )
583 .await
584 .unwrap()
585 .unwrap();
586
587 assert_matches!(
588 store.export(2).await.unwrap(),
589 Err(fsandbox::CapabilityStoreError::IdNotFound)
590 );
591 }
592
593 #[fuchsia::test]
594 async fn drop() {
595 let (store, stream) =
596 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
597 let _server = fasync::Task::spawn(async move {
598 let receiver_scope = fasync::Scope::new();
599 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
600 });
601
602 let (ch, _) = fidl::Channel::create();
603 let handle = ch.into_handle();
604 let handle_koid = handle.get_koid().unwrap();
605 let cap1 = Capability::Handle(handle.into());
606 let cap2 = Capability::Data(Data::Int64(42));
607 store
608 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
609 .await
610 .unwrap()
611 .unwrap();
612 store
613 .import(2, cap2.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
614 .await
615 .unwrap()
616 .unwrap();
617
618 store.drop(2).await.unwrap().unwrap();
620 assert_matches!(
621 store.export(1).await.unwrap(),
622 Ok(fsandbox::Capability::Handle(h)) if h.get_koid().unwrap() == handle_koid
623 );
624 assert_matches!(
625 store.export(2).await.unwrap(),
626 Err(fsandbox::CapabilityStoreError::IdNotFound)
627 );
628
629 let cap2 = Capability::Data(Data::Int64(84));
631 store
632 .import(2, cap2.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
633 .await
634 .unwrap()
635 .unwrap();
636 assert_matches!(
637 store.export(2).await.unwrap(),
638 Ok(fsandbox::Capability::Data(fsandbox::Data::Int64(i))) if i == 84
639 );
640 }
641
642 #[fuchsia::test]
643 async fn drop_error() {
644 let (store, stream) =
645 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
646 let _server = fasync::Task::spawn(async move {
647 let receiver_scope = fasync::Scope::new();
648 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
649 });
650
651 let cap1 = Capability::Data(Data::Int64(42));
652 store
653 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
654 .await
655 .unwrap()
656 .unwrap();
657
658 assert_matches!(
659 store.drop(2).await.unwrap(),
660 Err(fsandbox::CapabilityStoreError::IdNotFound)
661 );
662 }
663
664 #[fuchsia::test]
665 async fn duplicate() {
666 let (store, stream) =
667 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
668 let _server = fasync::Task::spawn(async move {
669 let receiver_scope = fasync::Scope::new();
670 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
671 });
672
673 let (event, _) = fidl::EventPair::create();
674 let handle = event.into_handle();
675 let handle_koid = handle.get_koid().unwrap();
676 let cap1 = Capability::Handle(handle.into());
677 store
678 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
679 .await
680 .unwrap()
681 .unwrap();
682 store.duplicate(1, 2).await.unwrap().unwrap();
683 store.drop(1).await.unwrap().unwrap();
684
685 let cap1 = store.export(2).await.unwrap().unwrap();
686 assert_matches!(
687 cap1,
688 fsandbox::Capability::Handle(h) if h.get_koid().unwrap() == handle_koid
689 );
690 }
691
692 #[fuchsia::test]
693 async fn duplicate_error() {
694 let (store, stream) =
695 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
696 let _server = fasync::Task::spawn(async move {
697 let receiver_scope = fasync::Scope::new();
698 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
699 });
700
701 assert_matches!(
702 store.duplicate(1, 2).await.unwrap(),
703 Err(fsandbox::CapabilityStoreError::IdNotFound)
704 );
705
706 let cap1 = Capability::Data(Data::Int64(42));
707 let cap2 = Capability::Data(Data::Int64(84));
708 store
709 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
710 .await
711 .unwrap()
712 .unwrap();
713 store
714 .import(2, cap2.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
715 .await
716 .unwrap()
717 .unwrap();
718 assert_matches!(
719 store.duplicate(1, 2).await.unwrap(),
720 Err(fsandbox::CapabilityStoreError::IdAlreadyExists)
721 );
722
723 let (ch, _) = fidl::Channel::create();
725 let handle = ch.into_handle();
726 let cap1 = Capability::Handle(handle.into());
727 store
728 .import(3, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
729 .await
730 .unwrap()
731 .unwrap();
732 assert_matches!(
733 store.duplicate(3, 4).await.unwrap(),
734 Err(fsandbox::CapabilityStoreError::NotDuplicatable)
735 );
736 }
737}