Delays PCAPNG file creation until first packet

This CL fixes b/257848589. The creation of log file is delayed until
first UCI packet is received by LogWriterActor. As a result, no log file
would be created had the logging been disabled throughout the usage.

Bug: 257848589
Test: cargo test
Test: make com.android.google.uwb with ag/19881044 cherry-picked
Change-Id: Id3841ca3f2fe4ca0e6706cde87e7cd14ef281e52
diff --git a/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs b/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs
index daaed2a..a00018b 100644
--- a/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs
+++ b/src/rust/uwb_core/src/uci/pcapng_uci_logger_factory.rs
@@ -136,7 +136,7 @@
     /// Maps chip id to interface id. The content follows the content of the component in
     /// PcapngUciLoggerFactory with the same name.
     chip_interface_id_map: Vec<String>,
-    current_file: BufferedFile,
+    current_file: Option<BufferedFile>,
     file_factory: FileFactory,
     file_size_limit: usize,
     log_receiver: mpsc::UnboundedReceiver<PcapngLoggerMessage>,
@@ -145,14 +145,23 @@
 impl LogWriterActor {
     /// write data to file.
     fn write_once(&mut self, data: Vec<u8>) -> Option<()> {
-        if data.len() + self.current_file.file_size() > self.file_size_limit {
-            self.current_file = self
-                .file_factory
-                .build_file_with_metadata(&self.chip_interface_id_map, self.file_size_limit)?;
+        // Create new file if the file is not created, or does not fit incoming data:
+        if self.current_file.is_none()
+            || data.len() + self.current_file.as_ref().unwrap().file_size() > self.file_size_limit
+        {
+            self.current_file = Some(
+                self.file_factory
+                    .build_file_with_metadata(&self.chip_interface_id_map, self.file_size_limit)?,
+            );
         }
-        self.current_file.buffered_write(data)
+        self.current_file.as_mut().unwrap().buffered_write(data)
     }
 
+    /// Handle single new chip: stores chip in chip_interface_id_map and:
+    ///
+    /// a. Nothing extra if current_file is not created yet.
+    /// b. If current file exists:
+    ///    Insert IDB in current file if it fits, otherwise switch to new file.
     fn handle_new_chip(&mut self, chip_id: String, interface_id: u32) -> Option<()> {
         if self.chip_interface_id_map.contains(&chip_id)
             || self.chip_interface_id_map.len() as u32 != interface_id
@@ -164,17 +173,20 @@
             return None;
         }
         self.chip_interface_id_map.push(chip_id.clone());
-        // Handle single new chip:
-        // Insert IDB in current file if it fits, otherwise switch to new file.
-        let idb_data = into_interface_description_block(chip_id)?;
-        if idb_data.len() + self.current_file.file_size() <= self.file_size_limit {
-            self.current_file.buffered_write(idb_data)
-        } else {
-            self.current_file = self
-                .file_factory
-                .build_file_with_metadata(&self.chip_interface_id_map, self.file_size_limit)?;
-            Some(())
+
+        if let Some(current_file) = &mut self.current_file {
+            let idb_data = into_interface_description_block(chip_id)?;
+            if idb_data.len() + current_file.file_size() <= self.file_size_limit {
+                current_file.buffered_write(idb_data)?;
+            } else {
+                self.current_file =
+                    Some(self.file_factory.build_file_with_metadata(
+                        &self.chip_interface_id_map,
+                        self.file_size_limit,
+                    )?);
+            }
         }
+        Some(())
     }
 
     async fn run(&mut self) {
@@ -189,10 +201,17 @@
                 }
                 Some(PcapngLoggerMessage::ByteStream(data)) => {
                     if self.write_once(data).is_none() {
-                        error!(
-                            "UCI log: failed writting packet to log file {:?}",
-                            self.current_file.file
-                        );
+                        match &self.current_file {
+                            Some(current_file) => {
+                                error!(
+                                    "UCI log: failed writting packet to log file {:?}",
+                                    current_file.file
+                                );
+                            }
+                            None => {
+                                error!("UCI log: failed writting packet to log file: no log file.");
+                            }
+                        }
                         break;
                     }
                 }
@@ -216,17 +235,15 @@
     ///
     /// runtime_handle must be a Handle to a multithread runtime that outlives LogWriterActor
     fn new(
-        mut file_factory: FileFactory,
+        file_factory: FileFactory,
         file_size_limit: usize,
         runtime_handle: Handle,
     ) -> Option<Self> {
         let chip_interface_id_map = Vec::new();
-        let current_file =
-            file_factory.build_file_with_metadata(&chip_interface_id_map, file_size_limit)?;
         let (log_sender, log_receiver) = mpsc::unbounded_channel();
         let mut log_writer_actor = LogWriterActor {
             chip_interface_id_map,
-            current_file,
+            current_file: None,
             file_factory,
             file_size_limit,
             log_receiver,
@@ -451,6 +468,28 @@
     }
 
     #[test]
+    fn test_no_file_write() {
+        let dir = tempdir().unwrap();
+        {
+            let runtime = Builder::new_multi_thread().enable_all().build().unwrap();
+            let mut file_manager = PcapngUciLoggerFactoryBuilder::new()
+                .buffer_size(1024)
+                .filename_prefix("log".to_owned())
+                .log_path(dir.as_ref().to_owned())
+                .runtime_handle(runtime.handle().to_owned())
+                .build()
+                .unwrap();
+            let _logger_0 = file_manager.build_logger("logger 0").unwrap();
+            let _logger_1 = file_manager.build_logger("logger 1").unwrap();
+            // Sleep needed to guarantee handling pending logs before runtime goes out of scope.
+            thread::sleep(time::Duration::from_millis(10));
+        }
+        // Expect no log file created as no packet is received.
+        let log_path = dir.as_ref().to_owned().join("log.pcapng");
+        assert!(fs::read(&log_path).is_err());
+    }
+
+    #[test]
     fn test_single_file_write() {
         let dir = tempdir().unwrap();
         {