isolated_swd/
cache.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::Error;
6
7/// Represents the sandboxed package cache.
8pub struct Cache {
9    _pkg_cache_proxy: fidl_fuchsia_pkg::PackageCacheProxy,
10}
11
12impl Cache {
13    /// Construct a new `Cache` object with pre-created proxies to package cache, and space
14    /// manager.
15    pub fn new_with_proxies(
16        pkg_cache_proxy: fidl_fuchsia_pkg::PackageCacheProxy,
17    ) -> Result<Self, Error> {
18        Ok(Self { _pkg_cache_proxy: pkg_cache_proxy })
19    }
20
21    /// Construct a new `Cache` object using capabilities available in the namespace of the component
22    /// calling this function. Should be the default in production usage, as these capabilities
23    /// should be statically routed (i.e. from `pkg-recovery.cml`).
24    pub fn new() -> Result<Self, Error> {
25        Ok(Self {
26            _pkg_cache_proxy: fuchsia_component::client::connect_to_protocol::<
27                fidl_fuchsia_pkg::PackageCacheMarker,
28            >()?,
29        })
30    }
31
32    /// Get a proxy to an instance of fuchsia.pkg.PackageCache.
33    #[cfg(test)]
34    pub fn package_cache_proxy(&self) -> Result<fidl_fuchsia_pkg::PackageCacheProxy, Error> {
35        Ok(self._pkg_cache_proxy.clone())
36    }
37}
38
39#[cfg(test)]
40pub(crate) mod for_tests {
41    use super::*;
42    use blobfs_ramdisk::BlobfsRamdisk;
43    use fidl::endpoints::{ServerEnd, SynchronousProxy};
44    use fuchsia_component_test::{
45        Capability, ChildOptions, ChildRef, RealmBuilder, RealmInstance, Ref, Route,
46    };
47    use futures::prelude::*;
48    use std::sync::Arc;
49    use {
50        fidl_fuchsia_fxfs as ffxfs, fidl_fuchsia_io as fio, fidl_fuchsia_metrics as fmetrics,
51        fuchsia_async as fasync,
52    };
53
54    pub struct CacheForTest {
55        pub blobfs: blobfs_ramdisk::BlobfsRamdisk,
56        pub cache: Arc<Cache>,
57    }
58
59    impl CacheForTest {
60        pub async fn realm_setup(
61            realm_builder: &RealmBuilder,
62            blobfs: &BlobfsRamdisk,
63        ) -> Result<ChildRef, Error> {
64            let blobfs_proxy = blobfs.root_dir_proxy().expect("getting root dir proxy");
65            let svc_dir = blobfs.svc_dir().expect("getting service dir proxy");
66
67            let local_mocks = realm_builder
68                .add_local_child(
69                    "pkg_cache_service_reflector",
70                    move |handles| {
71                        let mut fs = fuchsia_component::server::ServiceFs::new();
72                        let (creator_dir, server_end) =
73                            fidl::endpoints::create_sync_proxy::<fio::DirectoryMarker>();
74                        svc_dir
75                            .open(
76                                ".",
77                                fio::PERM_READABLE,
78                                &fio::Options::default(),
79                                server_end.into_channel(),
80                            )
81                            .unwrap();
82                        let (reader_dir, server_end) =
83                            fidl::endpoints::create_sync_proxy::<fio::DirectoryMarker>();
84                        svc_dir
85                            .open(
86                                ".",
87                                fio::PERM_READABLE,
88                                &fio::Options::default(),
89                                server_end.into_channel(),
90                            )
91                            .unwrap();
92                        // Not necessary for updates, but prevents spam of irrelevant error logs.
93                        fs.dir("svc")
94                            .add_fidl_service(move |stream| {
95                                fasync::Task::spawn(
96                                    Arc::new(mock_metrics::MockMetricEventLoggerFactory::new())
97                                        .run_logger_factory(stream),
98                                )
99                                .detach()
100                            })
101                            .add_service_connector(
102                                move |server_end: ServerEnd<ffxfs::BlobCreatorMarker>| {
103                                    fdio::service_connect_at(
104                                        creator_dir.as_channel(),
105                                        "fuchsia.fxfs.BlobCreator",
106                                        server_end.into_channel(),
107                                    )
108                                    .unwrap();
109                                },
110                            )
111                            .add_service_connector(
112                                move |server_end: ServerEnd<ffxfs::BlobReaderMarker>| {
113                                    fdio::service_connect_at(
114                                        reader_dir.as_channel(),
115                                        "fuchsia.fxfs.BlobReader",
116                                        server_end.into_channel(),
117                                    )
118                                    .unwrap();
119                                },
120                            );
121                        fs.add_remote("blob", Clone::clone(&blobfs_proxy));
122                        async move {
123                            fs.serve_connection(handles.outgoing_dir).unwrap();
124                            let () = fs.collect().await;
125                            Ok(())
126                        }
127                        .boxed()
128                    },
129                    ChildOptions::new(),
130                )
131                .await
132                .unwrap();
133
134            let pkg_cache = realm_builder
135                .add_child("pkg_cache", "#meta/pkg-cache.cm", ChildOptions::new())
136                .await
137                .unwrap();
138
139            realm_builder
140                .add_capability(cm_rust::CapabilityDecl::Config(cm_rust::ConfigurationDecl {
141                    name: "fuchsia.zircon.system.pkgfs.cmd".parse().unwrap(),
142                    value: "test".into(),
143                }))
144                .await
145                .unwrap();
146            realm_builder
147                .add_route(
148                    Route::new()
149                        .capability(Capability::configuration("fuchsia.zircon.system.pkgfs.cmd"))
150                        .from(Ref::self_())
151                        .to(&pkg_cache),
152                )
153                .await
154                .unwrap();
155            let pkg_cache_config = realm_builder
156                .add_child("pkg_cache_config", "#meta/pkg-cache-config.cm", ChildOptions::new())
157                .await
158                .unwrap();
159            realm_builder
160                .add_route(
161                    Route::new()
162                        .capability(Capability::configuration(
163                            "fuchsia.pkgcache.AllPackagesExecutable",
164                        ))
165                        .capability(Capability::configuration("fuchsia.pkgcache.UseSystemImage"))
166                        .capability(Capability::configuration(
167                            "fuchsia.pkgcache.EnableUpgradablePackages",
168                        ))
169                        .from(&pkg_cache_config)
170                        .to(&pkg_cache),
171                )
172                .await
173                .unwrap();
174            let system_update_committer = realm_builder
175                .add_child(
176                    "system-update-committer",
177                    "#meta/fake-system-update-committer.cm",
178                    ChildOptions::new(),
179                )
180                .await
181                .unwrap();
182
183            realm_builder
184                .add_route(
185                    Route::new()
186                        .capability(
187                            Capability::directory("blob-exec")
188                                .path("/blob")
189                                .rights(fio::RW_STAR_DIR | fio::Operations::EXECUTE),
190                        )
191                        .from(&local_mocks)
192                        .to(&pkg_cache),
193                )
194                .await
195                .unwrap();
196
197            realm_builder
198                .add_route(
199                    Route::new()
200                        .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
201                        .from(Ref::parent())
202                        .to(&pkg_cache),
203                )
204                .await
205                .unwrap();
206
207            realm_builder
208                .add_route(
209                    Route::new()
210                        .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobCreator"))
211                        .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobReader"))
212                        .from(&local_mocks)
213                        .to(&pkg_cache),
214                )
215                .await
216                .unwrap();
217
218            realm_builder
219                .add_route(
220                    Route::new()
221                        .capability(Capability::protocol_by_name("fuchsia.pkg.PackageCache"))
222                        .capability(Capability::protocol_by_name("fuchsia.pkg.RetainedPackages"))
223                        .capability(Capability::protocol_by_name(
224                            "fuchsia.pkg.garbagecollector.Manager",
225                        ))
226                        .from(&pkg_cache)
227                        .to(Ref::parent()),
228                )
229                .await
230                .unwrap();
231
232            realm_builder
233                .add_route(
234                    Route::new()
235                        .capability(Capability::protocol_by_name(
236                            "fuchsia.update.CommitStatusProvider",
237                        ))
238                        .from(&system_update_committer)
239                        .to(&pkg_cache),
240                )
241                .await
242                .unwrap();
243
244            realm_builder
245                .add_route(
246                    Route::new()
247                        .capability(
248                            Capability::protocol::<fmetrics::MetricEventLoggerFactoryMarker>(),
249                        )
250                        .from(&local_mocks)
251                        .to(&pkg_cache),
252                )
253                .await
254                .unwrap();
255            Ok(pkg_cache)
256        }
257
258        pub async fn new(
259            realm_instance: &RealmInstance,
260            blobfs: BlobfsRamdisk,
261        ) -> Result<Self, Error> {
262            let pkg_cache_proxy = realm_instance
263                .root
264                .connect_to_protocol_at_exposed_dir()
265                .expect("connect to pkg cache");
266
267            let cache = Cache::new_with_proxies(pkg_cache_proxy).unwrap();
268
269            Ok(CacheForTest { blobfs, cache: Arc::new(cache) })
270        }
271    }
272}
273
274#[cfg(test)]
275mod tests {
276    use super::for_tests::CacheForTest;
277    use fuchsia_async as fasync;
278    use fuchsia_component_test::RealmBuilder;
279
280    #[fasync::run_singlethreaded(test)]
281    pub async fn test_cache_handles_sync() {
282        let realm_builder = RealmBuilder::new().await.unwrap();
283        let blobfs = blobfs_ramdisk::BlobfsRamdisk::start().await.expect("starting blobfs");
284
285        let _cache_ref =
286            CacheForTest::realm_setup(&realm_builder, &blobfs).await.expect("setting up realm");
287        let realm_instance = realm_builder.build().await.unwrap();
288        let cache = CacheForTest::new(&realm_instance, blobfs).await.expect("launching cache");
289        let proxy = cache.cache.package_cache_proxy().unwrap();
290
291        assert_eq!(proxy.sync().await.unwrap(), Ok(()));
292    }
293}