Don't update idsig when it's already up-to-date

Bug: 193504400
Test: run atest virtualizationmanager_device_test
Test: run MicrodroidDemoApp. Start a VM, stop it, run it again. Observe
the timestamp of
/data/data/com.android.microdroid.demo/vm/test_vm/idsig. It's not
changed.

Change-Id: I2a0d600b70dd5cd83cc5244c4a51a7bccbc5962d
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 86c8596..9cd70e6 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -116,6 +116,20 @@
             .context("failed to create idsig")?;
 
     let mut output = clone_file(idsig_fd)?;
+
+    // Optimization. We don't have to update idsig file whenever a VM is started. Don't update it,
+    // if the idsig file already has the same APK digest.
+    if output.metadata()?.len() > 0 {
+        if let Ok(out_sig) = V4Signature::from_idsig(&mut output) {
+            if out_sig.signing_info.apk_digest == sig.signing_info.apk_digest {
+                debug!("idsig {:?} is up-to-date with apk {:?}.", output, input);
+                return Ok(());
+            }
+        }
+        // if we fail to read v4signature from output, that's fine. User can pass a random file.
+        // We will anyway overwrite the file to the v4signature generated from input_fd.
+    }
+
     output.set_len(0).context("failed to set_len on the idsig output")?;
     sig.write_into(&mut output).context("failed to write idsig")?;
     Ok(())
@@ -236,9 +250,6 @@
         input_fd: &ParcelFileDescriptor,
         idsig_fd: &ParcelFileDescriptor,
     ) -> binder::Result<()> {
-        // TODO(b/193504400): do this only when (1) idsig_fd is empty or (2) the APK digest in
-        // idsig_fd is different from APK digest in input_fd
-
         check_manage_access()?;
 
         create_or_update_idsig_file(input_fd, idsig_fd)
@@ -1300,4 +1311,30 @@
         assert!(ret.is_err(), "should fail");
         Ok(())
     }
+
+    #[test]
+    fn test_create_or_update_idsig_does_not_update_if_already_valid() -> Result<()> {
+        use std::io::Seek;
+
+        // Pick any APK
+        let mut apk = File::open("/system/priv-app/Shell/Shell.apk").unwrap();
+        let mut idsig = tempfile::tempfile().unwrap();
+
+        create_or_update_idsig_file(
+            &ParcelFileDescriptor::new(apk.try_clone()?),
+            &ParcelFileDescriptor::new(idsig.try_clone()?),
+        )?;
+        let modified_orig = idsig.metadata()?.modified()?;
+        apk.rewind()?;
+        idsig.rewind()?;
+
+        // Call the function again
+        create_or_update_idsig_file(
+            &ParcelFileDescriptor::new(apk.try_clone()?),
+            &ParcelFileDescriptor::new(idsig.try_clone()?),
+        )?;
+        let modified_new = idsig.metadata()?.modified()?;
+        assert!(modified_orig == modified_new, "idsig file was updated unnecessarily");
+        Ok(())
+    }
 }