[installer] Pause block watcher when writing FVM.

Otherwise fshost tries to start blobfs while it's being written, which
causes filesystem corruption.

Change-Id: Ia63fb19b9f9233be7b80fe8f742e7b021c30c988
diff --git a/src/recovery/system/BUILD.gn b/src/recovery/system/BUILD.gn
index cab04f0..05a78d7 100644
--- a/src/recovery/system/BUILD.gn
+++ b/src/recovery/system/BUILD.gn
@@ -221,6 +221,7 @@
   with_unit_tests = true
   deps = [
     "//sdk/fidl/fuchsia.device:fuchsia.device-rustc",
+    "//sdk/fidl/fuchsia.fshost:fuchsia.fshost-rustc",
     "//sdk/fidl/fuchsia.hardware.block:fuchsia.hardware.block-rustc",
     "//sdk/fidl/fuchsia.hardware.block.partition:fuchsia.hardware.block.partition-rustc",
     "//sdk/fidl/fuchsia.hardware.block.volume:fuchsia.hardware.block.volume-rustc",
diff --git a/src/recovery/system/installer/partition.rs b/src/recovery/system/installer/partition.rs
index 5d47598..c7ec364 100644
--- a/src/recovery/system/installer/partition.rs
+++ b/src/recovery/system/installer/partition.rs
@@ -6,6 +6,7 @@
     crate::installer::BootloaderType,
     anyhow::{anyhow, Context, Error},
     fidl::endpoints::Proxy,
+    fidl_fuchsia_fshost::{BlockWatcherMarker, BlockWatcherProxy},
     fidl_fuchsia_hardware_block_partition::PartitionProxy,
     fidl_fuchsia_mem::Buffer,
     fidl_fuchsia_paver::{Asset, Configuration, DynamicDataSinkProxy, PayloadStreamMarker},
@@ -16,6 +17,31 @@
     std::{fmt, fs, io::Read, path::Path},
 };
 
+struct BlockWatcherPauser {
+    proxy: Option<BlockWatcherProxy>,
+}
+
+impl BlockWatcherPauser {
+    pub async fn new() -> Result<Self, Error> {
+        let connection = fuchsia_component::client::connect_to_protocol::<BlockWatcherMarker>()
+            .context("Connecting to block watcher")?;
+        zx::Status::ok(connection.pause().await.context("Sending pause")?)
+            .context("Pausing block watcher")?;
+        Ok(BlockWatcherPauser { proxy: Some(connection) })
+    }
+
+    pub async fn resume(mut self) -> Result<(), Error> {
+        zx::Status::ok(self.proxy.take().unwrap().resume().await.context("Sending resume")?)
+            .context("Resuming block watcher")
+    }
+}
+
+impl Drop for BlockWatcherPauser {
+    fn drop(&mut self) {
+        assert!(self.proxy.is_none())
+    }
+}
+
 #[derive(Debug, PartialEq)]
 pub enum PartitionPaveType {
     Asset { r#type: Asset, config: Configuration },
@@ -195,6 +221,7 @@
                 data_sink.write_bootloader(&mut fidl_buf).await?;
             }
             PartitionPaveType::Volume => {
+                let pauser = BlockWatcherPauser::new().await.context("Pausing block watcher")?;
                 // Set up a PayloadStream to serve the data sink.
                 let file =
                     Box::new(fs::File::open(Path::new(&self.src)).context("Opening partition")?);
@@ -214,6 +241,7 @@
                 .detach();
                 // Tell the data sink to use our PayloadStream.
                 data_sink.write_volumes(client_end).await?;
+                pauser.resume().await.context("Resuming block watcher")?;
             }
         };
         Ok(())
diff --git a/src/recovery/system/meta/system_recovery_installer.cmx b/src/recovery/system/meta/system_recovery_installer.cmx
index a19e0bb..c7bff80 100644
--- a/src/recovery/system/meta/system_recovery_installer.cmx
+++ b/src/recovery/system/meta/system_recovery_installer.cmx
@@ -23,6 +23,7 @@
             "root-ssl-certificates"
         ],
         "services": [
+            "fuchsia.fshost.BlockWatcher",
             "fuchsia.paver.Paver",
             "fuchsia.process.Launcher",
             "fuchsia.recovery.FactoryReset",