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