Skip to main content

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 fidl_fuchsia_fxfs as ffxfs;
45    use fidl_fuchsia_io as fio;
46    use fidl_fuchsia_metrics as fmetrics;
47    use fuchsia_async as fasync;
48    use fuchsia_component_test::{
49        Capability, ChildOptions, ChildRef, RealmBuilder, RealmInstance, Ref, Route,
50    };
51    use futures::prelude::*;
52    use std::sync::Arc;
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            let system_image_package = fuchsia_pkg_testing::SystemImageBuilder::new().build().await;
140            system_image_package.write_to_blobfs(blobfs).await;
141
142            for (name, value) in [
143                ("fuchsia.zircon.system.pkgfs.cmd", system_image_package.hash().to_string().into()),
144                ("fuchsia.pkgcache.AllPackagesExecutable", false.into()),
145                ("fuchsia.pkgcache.RequireSystemImage", false.into()),
146                ("fuchsia.pkgcache.EnableUpgradablePackages", false.into()),
147            ] {
148                realm_builder
149                    .add_capability(
150                        cm_rust::ConfigurationDecl { name: name.parse().unwrap(), value }.into(),
151                    )
152                    .await
153                    .unwrap();
154                realm_builder
155                    .add_route(
156                        Route::new()
157                            .capability(Capability::configuration(name))
158                            .from(Ref::self_())
159                            .to(&pkg_cache),
160                    )
161                    .await
162                    .unwrap();
163            }
164            let system_update_committer = realm_builder
165                .add_child(
166                    "system-update-committer",
167                    "#meta/fake-system-update-committer.cm",
168                    ChildOptions::new(),
169                )
170                .await
171                .unwrap();
172
173            realm_builder
174                .add_route(
175                    Route::new()
176                        .capability(
177                            Capability::directory("blob-exec")
178                                .path("/blob")
179                                .rights(fio::RW_STAR_DIR | fio::Operations::EXECUTE),
180                        )
181                        .from(&local_mocks)
182                        .to(&pkg_cache),
183                )
184                .await
185                .unwrap();
186
187            realm_builder
188                .add_route(
189                    Route::new()
190                        .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
191                        .from(Ref::parent())
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.fxfs.BlobCreator"))
201                        .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobReader"))
202                        .from(&local_mocks)
203                        .to(&pkg_cache),
204                )
205                .await
206                .unwrap();
207
208            realm_builder
209                .add_route(
210                    Route::new()
211                        .capability(Capability::protocol_by_name("fuchsia.pkg.PackageCache"))
212                        .capability(Capability::protocol_by_name("fuchsia.pkg.RetainedPackages"))
213                        .capability(Capability::protocol_by_name(
214                            "fuchsia.pkg.garbagecollector.Manager",
215                        ))
216                        .from(&pkg_cache)
217                        .to(Ref::parent()),
218                )
219                .await
220                .unwrap();
221
222            realm_builder
223                .add_route(
224                    Route::new()
225                        .capability(Capability::protocol_by_name(
226                            "fuchsia.update.CommitStatusProvider",
227                        ))
228                        .from(&system_update_committer)
229                        .to(&pkg_cache),
230                )
231                .await
232                .unwrap();
233
234            realm_builder
235                .add_route(
236                    Route::new()
237                        .capability(
238                            Capability::protocol::<fmetrics::MetricEventLoggerFactoryMarker>(),
239                        )
240                        .from(&local_mocks)
241                        .to(&pkg_cache),
242                )
243                .await
244                .unwrap();
245            Ok(pkg_cache)
246        }
247
248        pub async fn new(
249            realm_instance: &RealmInstance,
250            blobfs: BlobfsRamdisk,
251        ) -> Result<Self, Error> {
252            let pkg_cache_proxy = realm_instance
253                .root
254                .connect_to_protocol_at_exposed_dir()
255                .expect("connect to pkg cache");
256
257            let cache = Cache::new_with_proxies(pkg_cache_proxy).unwrap();
258
259            Ok(CacheForTest { blobfs, cache: Arc::new(cache) })
260        }
261    }
262}
263
264#[cfg(test)]
265mod tests {
266    use super::for_tests::CacheForTest;
267    use fuchsia_async as fasync;
268    use fuchsia_component_test::RealmBuilder;
269
270    #[fasync::run_singlethreaded(test)]
271    pub async fn test_cache_handles_sync() {
272        let realm_builder = RealmBuilder::new().await.unwrap();
273        let blobfs = blobfs_ramdisk::BlobfsRamdisk::start().await.expect("starting blobfs");
274
275        let _cache_ref =
276            CacheForTest::realm_setup(&realm_builder, &blobfs).await.expect("setting up realm");
277        let realm_instance = realm_builder.build().await.unwrap();
278        let cache = CacheForTest::new(&realm_instance, blobfs).await.expect("launching cache");
279        let proxy = cache.cache.package_cache_proxy().unwrap();
280
281        assert_eq!(proxy.sync().await.unwrap(), Ok(()));
282    }
283}