Remove file size from authfs flags

authfs used to take flags like `--remote-unverified-file 5:10:40960`
where the 40969 is the file size provided by the client. The intention
is that since the file is readonly, we can set up the FUSE with the
information ready, and avoid requesting the size on every stat(2)-like
syscall.

It's just that this make it harder to use for authfs' clients. This
change remove the needs for the clients to provide the size. Instead,
authfs internally just query fd_server before starting the FUSE.

Bug: 198824883
Test: atest AuthFsHostTest ComposHostTestCases
Change-Id: I9b26b6e13bfa170d766a2428cb485d97e0423e13
diff --git a/authfs/aidl/com/android/virt/fs/IVirtFdService.aidl b/authfs/aidl/com/android/virt/fs/IVirtFdService.aidl
index d3c0979..a565a6f 100644
--- a/authfs/aidl/com/android/virt/fs/IVirtFdService.aidl
+++ b/authfs/aidl/com/android/virt/fs/IVirtFdService.aidl
@@ -28,6 +28,9 @@
      */
     const int ERROR_IO = 2;
 
+    /** Error when the file is too large to handle correctly. */
+    const int ERROR_FILE_TOO_LARGE = 3;
+
     /** Maximum content size that the service allows the client to request. */
     const int MAX_REQUESTING_DATA = 16384;
 
@@ -54,4 +57,6 @@
 
     /** Resizes the file backed by the given file ID to the new size. */
     void resize(int id, long size);
+
+    long getFileSize(int id);
 }
diff --git a/authfs/aidl/com/android/virt/fs/InputFdAnnotation.aidl b/authfs/aidl/com/android/virt/fs/InputFdAnnotation.aidl
index dafb137..3534a77 100644
--- a/authfs/aidl/com/android/virt/fs/InputFdAnnotation.aidl
+++ b/authfs/aidl/com/android/virt/fs/InputFdAnnotation.aidl
@@ -23,7 +23,4 @@
      * number used in the backend server.
      */
     int fd;
-
-    /** The actual file size in bytes of the backing file to be read. */
-    long fileSize;
 }
diff --git a/authfs/fd_server/src/main.rs b/authfs/fd_server/src/main.rs
index d63fe93..4f17c83 100644
--- a/authfs/fd_server/src/main.rs
+++ b/authfs/fd_server/src/main.rs
@@ -27,6 +27,9 @@
 
 mod fsverity;
 
+use anyhow::{bail, Context, Result};
+use binder::unstable_api::AsNative;
+use log::{debug, error};
 use std::cmp::min;
 use std::collections::BTreeMap;
 use std::convert::TryInto;
@@ -36,12 +39,9 @@
 use std::os::unix::fs::FileExt;
 use std::os::unix::io::{AsRawFd, FromRawFd};
 
-use anyhow::{bail, Context, Result};
-use binder::unstable_api::AsNative;
-use log::{debug, error};
-
 use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService::{
-    BnVirtFdService, IVirtFdService, ERROR_IO, ERROR_UNKNOWN_FD, MAX_REQUESTING_DATA,
+    BnVirtFdService, IVirtFdService, ERROR_FILE_TOO_LARGE, ERROR_IO, ERROR_UNKNOWN_FD,
+    MAX_REQUESTING_DATA,
 };
 use authfs_aidl_interface::binder::{
     add_service, BinderFeatures, ExceptionCode, Interface, ProcessState, Result as BinderResult,
@@ -226,6 +226,30 @@
             }
         }
     }
+
+    fn getFileSize(&self, id: i32) -> BinderResult<i64> {
+        match &self.get_file_config(id)? {
+            FdConfig::Readonly { file, .. } => {
+                let size = file
+                    .metadata()
+                    .map_err(|e| {
+                        error!("getFileSize error: {}", e);
+                        Status::from(ERROR_IO)
+                    })?
+                    .len();
+                Ok(size.try_into().map_err(|e| {
+                    error!("getFileSize: File too large: {}", e);
+                    Status::from(ERROR_FILE_TOO_LARGE)
+                })?)
+            }
+            FdConfig::ReadWrite(_file) => {
+                // Content and metadata of a writable file needs to be tracked by authfs, since
+                // fd_server isn't considered trusted. So there is no point to support getFileSize
+                // for a writable file.
+                Err(new_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION, "Unsupported"))
+            }
+        }
+    }
 }
 
 fn read_into_buf(file: &File, max_size: usize, offset: u64) -> io::Result<Vec<u8>> {
diff --git a/authfs/service/src/authfs.rs b/authfs/service/src/authfs.rs
index 7a466d3..f41a3a6 100644
--- a/authfs/service/src/authfs.rs
+++ b/authfs/service/src/authfs.rs
@@ -129,7 +129,7 @@
         // TODO(b/185178698): Many input files need to be signed and verified.
         // or can we use debug cert for now, which is better than nothing?
         args.push(OsString::from("--remote-ro-file-unverified"));
-        args.push(OsString::from(format!("{}:{}:{}", conf.fd, conf.fd, conf.fileSize)));
+        args.push(OsString::from(format!("{}:{}", conf.fd, conf.fd)));
     }
     for conf in out_fds {
         args.push(OsString::from("--remote-new-rw-file"));
diff --git a/authfs/src/main.rs b/authfs/src/main.rs
index 32ea3de..e004b81 100644
--- a/authfs/src/main.rs
+++ b/authfs/src/main.rs
@@ -29,6 +29,7 @@
 
 use anyhow::{bail, Context, Result};
 use std::collections::BTreeMap;
+use std::convert::TryInto;
 use std::fs::File;
 use std::io::Read;
 use std::path::{Path, PathBuf};
@@ -62,16 +63,15 @@
 
     /// A read-only remote file with integrity check. Can be multiple.
     ///
-    /// For example, `--remote-verified-file 5:10:1234:/path/to/cert` tells the filesystem to
-    /// associate entry 5 with a remote file 10 of size 1234 bytes, and need to be verified against
-    /// the /path/to/cert.
+    /// For example, `--remote-verified-file 5:10:/path/to/cert` tells the filesystem to associate
+    /// entry 5 with a remote file 10, and need to be verified against the /path/to/cert.
     #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
     remote_ro_file: Vec<OptionRemoteRoFile>,
 
     /// A read-only remote file without integrity check. Can be multiple.
     ///
-    /// For example, `--remote-unverified-file 5:10:1234` tells the filesystem to associate entry 5
-    /// with a remote file 10 of size 1234 bytes.
+    /// For example, `--remote-unverified-file 5:10` tells the filesystem to associate entry 5
+    /// with a remote file 10.
     #[structopt(long, parse(try_from_str = parse_remote_ro_file_unverified_option))]
     remote_ro_file_unverified: Vec<OptionRemoteRoFileUnverified>,
 
@@ -109,10 +109,6 @@
     /// ID to refer to the remote file.
     remote_id: i32,
 
-    /// Expected size of the remote file. Necessary for signature check and Merkle tree
-    /// verification.
-    file_size: u64,
-
     /// Certificate to verify the authenticity of the file's fs-verity signature.
     /// TODO(170494765): Implement PKCS#7 signature verification.
     _certificate_path: PathBuf,
@@ -123,9 +119,6 @@
 
     /// ID to refer to the remote file.
     remote_id: i32,
-
-    /// Expected size of the remote file.
-    file_size: u64,
 }
 
 struct OptionRemoteRwFile {
@@ -161,26 +154,24 @@
 
 fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
     let strs: Vec<&str> = option.split(':').collect();
-    if strs.len() != 4 {
+    if strs.len() != 3 {
         bail!("Invalid option: {}", option);
     }
     Ok(OptionRemoteRoFile {
         ino: strs[0].parse::<Inode>()?,
         remote_id: strs[1].parse::<i32>()?,
-        file_size: strs[2].parse::<u64>()?,
-        _certificate_path: PathBuf::from(strs[3]),
+        _certificate_path: PathBuf::from(strs[2]),
     })
 }
 
 fn parse_remote_ro_file_unverified_option(option: &str) -> Result<OptionRemoteRoFileUnverified> {
     let strs: Vec<&str> = option.split(':').collect();
-    if strs.len() != 3 {
+    if strs.len() != 2 {
         bail!("Invalid option: {}", option);
     }
     Ok(OptionRemoteRoFileUnverified {
         ino: strs[0].parse::<Inode>()?,
         remote_id: strs[1].parse::<i32>()?,
-        file_size: strs[2].parse::<u64>()?,
     })
 }
 
@@ -292,7 +283,7 @@
                 new_config_remote_verified_file(
                     service.clone(),
                     config.remote_id,
-                    config.file_size,
+                    service.getFileSize(config.remote_id)?.try_into()?,
                 )?,
             );
         }
@@ -303,7 +294,7 @@
                 new_config_remote_unverified_file(
                     service.clone(),
                     config.remote_id,
-                    config.file_size,
+                    service.getFileSize(config.remote_id)?.try_into()?,
                 )?,
             );
         }
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
index 6e1c890..e03e9c0 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
@@ -154,8 +154,7 @@
                 "--ro-fds 3:4:5 --ro-fds 6 --rpc-binder");
 
         runAuthFsOnMicrodroid(
-                "--remote-ro-file-unverified 10:6:4194304 --remote-ro-file 11:3:4194304:cert.der"
-                        + " --cid 2");
+                "--remote-ro-file-unverified 10:6 --remote-ro-file 11:3:cert.der --cid 2");
 
         // Action
         String actualHashUnverified4m = computeFileHashOnMicrodroid(MOUNT_DIR + "/10");
@@ -179,7 +178,7 @@
                         + " 6<input.4k1 7<input.4k1.merkle_dump 8<input.4k1.fsv_sig",
                 "--ro-fds 3:4:5 --ro-fds 6:7:8 --rpc-binder");
         runAuthFsOnMicrodroid(
-                "--remote-ro-file 10:3:4096:cert.der --remote-ro-file 11:6:4097:cert.der --cid 2");
+                "--remote-ro-file 10:3:cert.der --remote-ro-file 11:6:cert.der --cid 2");
 
         // Action
         String actualHash4k = computeFileHashOnMicrodroid(MOUNT_DIR + "/10");
@@ -200,7 +199,7 @@
         runFdServerOnAndroid(
                 "3<input.4m 4<input.4m.merkle_dump.bad 5<input.4m.fsv_sig",
                 "--ro-fds 3:4:5 --rpc-binder");
-        runAuthFsOnMicrodroid("--remote-ro-file 10:3:4096:cert.der --cid 2");
+        runAuthFsOnMicrodroid("--remote-ro-file 10:3:cert.der --cid 2");
 
         // Verify
         assertFalse(copyFileOnMicrodroid(MOUNT_DIR + "/10", "/dev/null"));