1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use {
    anyhow::Error,
    fidl::endpoints::{create_endpoints, ClientEnd},
    fidl_fuchsia_sysmem2 as fsysmem2, fidl_fuchsia_ui_composition as fland,
    fsysmem2::BufferCollectionTokenDuplicateRequest,
    fuchsia_zircon::{self as zx, AsHandleRef},
};

// Pair of tokens to be used with Scenic Allocator FIDL protocol.
pub struct BufferCollectionTokenPair {
    pub export_token: fland::BufferCollectionExportToken,
    pub import_token: fland::BufferCollectionImportToken,
}

impl BufferCollectionTokenPair {
    pub fn new() -> BufferCollectionTokenPair {
        let (raw_export_token, raw_import_token) = zx::EventPair::create();
        BufferCollectionTokenPair {
            export_token: fland::BufferCollectionExportToken { value: raw_export_token },
            import_token: fland::BufferCollectionImportToken { value: raw_import_token },
        }
    }
}

/// Given a Scenic `BufferCollectionImportToken`, returns a new version which has been duplicated.
pub fn duplicate_buffer_collection_import_token(
    import_token: &fland::BufferCollectionImportToken,
) -> Result<fland::BufferCollectionImportToken, Error> {
    let handle = import_token.value.as_handle_ref().duplicate(zx::Rights::SAME_RIGHTS)?;
    Ok(fland::BufferCollectionImportToken { value: handle.into() })
}

/// Calls `BufferCollectionToken.Duplicate()` on the provided token, passing the server end of a
/// newly-instantiated channel.  Then, calls `Sync()` on the provided token, so that the returned
/// token is safe to use immediately (i.e. the server has acknowledged that the duplication has
/// occurred).
pub async fn duplicate_buffer_collection_token(
    token: &mut fsysmem2::BufferCollectionTokenProxy,
) -> Result<ClientEnd<fsysmem2::BufferCollectionTokenMarker>, Error> {
    let (duplicate_token, duplicate_token_server_end) =
        create_endpoints::<fsysmem2::BufferCollectionTokenMarker>();

    token.duplicate(BufferCollectionTokenDuplicateRequest {
        rights_attenuation_mask: Some(fidl::Rights::SAME_RIGHTS),
        token_request: Some(duplicate_token_server_end),
        ..Default::default()
    })?;
    token.sync().await?;

    Ok(duplicate_token)
}