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            realm_builder
165                .add_route(
166                    Route::new()
167                        .capability(Capability::configuration(
168                            "fuchsia.pkgcache.BlobFetchConcurrencyLimit",
169                        ))
170                        .capability(Capability::configuration(
171                            "fuchsia.pkgcache.BlobNetworkHeaderTimeoutSeconds",
172                        ))
173                        .capability(Capability::configuration(
174                            "fuchsia.pkgcache.BlobNetworkBodyTimeoutSeconds",
175                        ))
176                        .capability(Capability::configuration(
177                            "fuchsia.pkgcache.BlobDownloadResumptionAttemptsLimit",
178                        ))
179                        .from(Ref::void())
180                        .to(&pkg_cache),
181                )
182                .await
183                .unwrap();
184            let system_update_committer = realm_builder
185                .add_child(
186                    "system-update-committer",
187                    "#meta/fake-system-update-committer.cm",
188                    ChildOptions::new(),
189                )
190                .await
191                .unwrap();
192
193            realm_builder
194                .add_route(
195                    Route::new()
196                        .capability(
197                            Capability::directory("blob-exec")
198                                .path("/blob")
199                                .rights(fio::RW_STAR_DIR | fio::Operations::EXECUTE),
200                        )
201                        .from(&local_mocks)
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.logger.LogSink"))
211                        .from(Ref::parent())
212                        .to(&pkg_cache),
213                )
214                .await
215                .unwrap();
216
217            realm_builder
218                .add_route(
219                    Route::new()
220                        .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobCreator"))
221                        .capability(Capability::protocol_by_name("fuchsia.fxfs.BlobReader"))
222                        .from(&local_mocks)
223                        .to(&pkg_cache),
224                )
225                .await
226                .unwrap();
227
228            realm_builder
229                .add_route(
230                    Route::new()
231                        .capability(Capability::protocol_by_name("fuchsia.pkg.PackageCache"))
232                        .capability(Capability::protocol_by_name("fuchsia.pkg.RetainedPackages"))
233                        .capability(Capability::protocol_by_name(
234                            "fuchsia.pkg.garbagecollector.Manager",
235                        ))
236                        .from(&pkg_cache)
237                        .to(Ref::parent()),
238                )
239                .await
240                .unwrap();
241
242            realm_builder
243                .add_route(
244                    Route::new()
245                        .capability(Capability::protocol_by_name(
246                            "fuchsia.update.CommitStatusProvider",
247                        ))
248                        .from(&system_update_committer)
249                        .to(&pkg_cache),
250                )
251                .await
252                .unwrap();
253
254            realm_builder
255                .add_route(
256                    Route::new()
257                        .capability(
258                            Capability::protocol::<fmetrics::MetricEventLoggerFactoryMarker>(),
259                        )
260                        .from(&local_mocks)
261                        .to(&pkg_cache),
262                )
263                .await
264                .unwrap();
265            Ok(pkg_cache)
266        }
267
268        pub async fn new(
269            realm_instance: &RealmInstance,
270            blobfs: BlobfsRamdisk,
271        ) -> Result<Self, Error> {
272            let pkg_cache_proxy = realm_instance
273                .root
274                .connect_to_protocol_at_exposed_dir()
275                .expect("connect to pkg cache");
276
277            let cache = Cache::new_with_proxies(pkg_cache_proxy).unwrap();
278
279            Ok(CacheForTest { blobfs, cache: Arc::new(cache) })
280        }
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use super::for_tests::CacheForTest;
287    use fuchsia_component_test::RealmBuilder;
288
289    #[fuchsia::test]
290    pub async fn test_cache_handles_sync() {
291        let realm_builder = RealmBuilder::new().await.unwrap();
292        let blobfs = blobfs_ramdisk::BlobfsRamdisk::start().await.expect("starting blobfs");
293
294        let _cache_ref =
295            CacheForTest::realm_setup(&realm_builder, &blobfs).await.expect("setting up realm");
296        let realm_instance = realm_builder.build().await.unwrap();
297        let cache = CacheForTest::new(&realm_instance, blobfs).await.expect("launching cache");
298        let proxy = cache.cache.package_cache_proxy().unwrap();
299
300        assert_eq!(proxy.sync().await.unwrap(), Ok(()));
301    }
302}