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