Support remote directories in authfs_service

Also take advantage of the new nested type in AIDL.

Bug: 205750213
Test: Can use the API locally
Change-Id: I8f7e63dedeb6dd72433f70807dcc65288c702097
diff --git a/authfs/aidl/com/android/virt/fs/AuthFsConfig.aidl b/authfs/aidl/com/android/virt/fs/AuthFsConfig.aidl
index dfccee5..2e3479c 100644
--- a/authfs/aidl/com/android/virt/fs/AuthFsConfig.aidl
+++ b/authfs/aidl/com/android/virt/fs/AuthFsConfig.aidl
@@ -16,11 +16,52 @@
 
 package com.android.virt.fs;
 
-import com.android.virt.fs.InputFdAnnotation;
-import com.android.virt.fs.OutputFdAnnotation;
-
 /** @hide */
 parcelable AuthFsConfig {
+    parcelable InputFdAnnotation {
+        /**
+         * File descriptor number to be passed to the program.  This is also the same file
+         * descriptor number used in the backend server.
+         */
+        int fd;
+    }
+
+    parcelable OutputFdAnnotation {
+        /**
+         * File descriptor number to be passed to the program.  This is also the same file
+         * descriptor number used in the backend server.
+         */
+        int fd;
+    }
+
+    parcelable InputDirFdAnnotation {
+        /**
+         * File descriptor number to be passed to the program.  This is also the same file
+         * descriptor number used in the backend server.
+         */
+        int fd;
+
+        /**
+         * A manifest file that includes serialized protobuf of
+         * android.security.fsverity.FSVerityDigests. The path must be accessible to the
+         * IAuthFsService.
+         */
+        String manifestPath;
+
+        /**
+         * Prefix path that should be stripped from the path in the manifest.
+         */
+        String prefix;
+    }
+
+    parcelable OutputDirFdAnnotation {
+        /**
+         * File descriptor number to be passed to the program.  This is also the same file
+         * descriptor number used in the backend server.
+         */
+        int fd;
+    }
+
     /** Port of the filesystem backend. */
     int port;
 
@@ -29,4 +70,10 @@
 
     /** Annotation for the remote output file descriptors. */
     OutputFdAnnotation[] outputFdAnnotations;
+
+    /** Annotation for the remote input directory descriptors. */
+    InputDirFdAnnotation[] inputDirFdAnnotations;
+
+    /** Annotation for the remote output directory descriptors. */
+    OutputDirFdAnnotation[] outputDirFdAnnotations;
 }
diff --git a/authfs/aidl/com/android/virt/fs/InputFdAnnotation.aidl b/authfs/aidl/com/android/virt/fs/InputFdAnnotation.aidl
deleted file mode 100644
index 3534a77..0000000
--- a/authfs/aidl/com/android/virt/fs/InputFdAnnotation.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virt.fs;
-
-/** @hide */
-parcelable InputFdAnnotation {
-    /**
-     * File descriptor number to be passed to the program.  This is also the same file descriptor
-     * number used in the backend server.
-     */
-    int fd;
-}
diff --git a/authfs/aidl/com/android/virt/fs/OutputFdAnnotation.aidl b/authfs/aidl/com/android/virt/fs/OutputFdAnnotation.aidl
deleted file mode 100644
index 4e4e621..0000000
--- a/authfs/aidl/com/android/virt/fs/OutputFdAnnotation.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.virt.fs;
-
-/** @hide */
-parcelable OutputFdAnnotation {
-    /**
-     * File descriptor number to be passed to the program.  This is currently assumed to be same as
-     * the file descriptor number used in the backend server.
-     */
-    int fd;
-}
diff --git a/authfs/service/src/authfs.rs b/authfs/service/src/authfs.rs
index 1b05749..2d4f707 100644
--- a/authfs/service/src/authfs.rs
+++ b/authfs/service/src/authfs.rs
@@ -26,11 +26,11 @@
 use std::thread::sleep;
 use std::time::{Duration, Instant};
 
-use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFs::{BnAuthFs, IAuthFs};
-use authfs_aidl_interface::aidl::com::android::virt::fs::{
-    AuthFsConfig::AuthFsConfig, InputFdAnnotation::InputFdAnnotation,
-    OutputFdAnnotation::OutputFdAnnotation,
+use authfs_aidl_interface::aidl::com::android::virt::fs::AuthFsConfig::{
+    AuthFsConfig, InputDirFdAnnotation::InputDirFdAnnotation, InputFdAnnotation::InputFdAnnotation,
+    OutputDirFdAnnotation::OutputDirFdAnnotation, OutputFdAnnotation::OutputFdAnnotation,
 };
+use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFs::{BnAuthFs, IAuthFs};
 use authfs_aidl_interface::binder::{
     self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Strong,
 };
@@ -80,6 +80,8 @@
             &mountpoint,
             &config.inputFdAnnotations,
             &config.outputFdAnnotations,
+            &config.inputDirFdAnnotations,
+            &config.outputDirFdAnnotations,
             debuggable,
         )?;
         wait_until_authfs_ready(&child, &mountpoint).map_err(|e| {
@@ -121,29 +123,41 @@
 
 fn run_authfs(
     mountpoint: &OsStr,
-    in_fds: &[InputFdAnnotation],
-    out_fds: &[OutputFdAnnotation],
+    in_file_fds: &[InputFdAnnotation],
+    out_file_fds: &[OutputFdAnnotation],
+    in_dir_fds: &[InputDirFdAnnotation],
+    out_dir_fds: &[OutputDirFdAnnotation],
     debuggable: bool,
 ) -> Result<SharedChild> {
     let mut args = vec![mountpoint.to_owned(), OsString::from("--cid=2")];
     args.push(OsString::from("-o"));
     args.push(OsString::from("fscontext=u:object_r:authfs_fuse:s0"));
-    for conf in in_fds {
+    for conf in in_file_fds {
         // 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(conf.fd.to_string()));
     }
-    for conf in out_fds {
+    for conf in out_file_fds {
         args.push(OsString::from("--remote-new-rw-file"));
         args.push(OsString::from(conf.fd.to_string()));
     }
+    for conf in in_dir_fds {
+        args.push(OsString::from("--remote-ro-dir"));
+        // TODO(206869687): Replace /dev/null with the real path when possible.
+        args.push(OsString::from(format!("{}:{}:{}", conf.fd, conf.manifestPath, conf.prefix)));
+    }
+    for conf in out_dir_fds {
+        args.push(OsString::from("--remote-new-rw-dir"));
+        args.push(OsString::from(conf.fd.to_string()));
+    }
     if debuggable {
         args.push(OsString::from("--debug"));
     }
 
     let mut command = Command::new(AUTHFS_BIN);
     command.args(&args);
+    debug!("Spawn authfs: {:?}", command);
     SharedChild::spawn(&mut command).context("Spawn authfs")
 }
 
diff --git a/authfs/src/main.rs b/authfs/src/main.rs
index 24b041c..f0c94c5 100644
--- a/authfs/src/main.rs
+++ b/authfs/src/main.rs
@@ -129,7 +129,7 @@
     /// A mapping file that describes the expecting file/directory structure and integrity metadata
     /// in the remote directory. The file contains serialized protobuf of
     /// android.security.fsverity.FSVerityDigests.
-    /// TODO(203251769): Really use the file when it's generated.
+    /// TODO(206869687): Really use the file when it's generated.
     #[allow(dead_code)]
     mapping_file_path: PathBuf,
 
@@ -252,7 +252,7 @@
             AuthFsEntry::ReadonlyDirectory { dir: InMemoryDir::new() },
         )?;
 
-        // TODO(203251769): Read actual path from config.mapping_file_path when it's generated.
+        // TODO(206869687): Read actual path from config.mapping_file_path when it's generated.
         let paths = vec![
             Path::new("/system/framework/framework.jar"),
             Path::new("/system/framework/services.jar"),
@@ -268,7 +268,7 @@
                     related_path,
                 )?;
                 let file_size = service.getFileSize(remote_file.get_remote_fd())?.try_into()?;
-                // TODO(203251769): Switch to VerifiedReadonly
+                // TODO(206869687): Switch to VerifiedReadonly
                 AuthFsEntry::UnverifiedReadonly { reader: remote_file, file_size }
             };
             authfs.add_entry_at_ro_dir_by_path(
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
index 70d48c2..c27c5cd 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
@@ -412,7 +412,7 @@
         // Setup
         String authfsInputDir = MOUNT_DIR + "/3";
         runFdServerOnAndroid("--open-dir 3:/system", "--ro-dirs 3");
-        // TODO(203251769): Replace /dev/null with real manifest file when it's generated. We
+        // TODO(206869687): Replace /dev/null with real manifest file when it's generated. We
         // currently hard-coded the files for the test manually, and ignore the integrity check.
         runAuthFsOnMicrodroid("--remote-ro-dir 3:/dev/null:/system --cid " + VMADDR_CID_HOST);
 
@@ -430,7 +430,7 @@
         // Setup
         String authfsInputDir = MOUNT_DIR + "/3";
         runFdServerOnAndroid("--open-dir 3:/system", "--ro-dirs 3");
-        // TODO(203251769): Replace /dev/null with real manifest file when it's generated. We
+        // TODO(206869687): Replace /dev/null with real manifest file when it's generated. We
         // currently hard-coded the files for the test manually, and ignore the integrity check.
         runAuthFsOnMicrodroid("--remote-ro-dir 3:/dev/null:/system --cid " + VMADDR_CID_HOST);
 
diff --git a/compos/src/compilation.rs b/compos/src/compilation.rs
index 1499d4b..72dca14 100644
--- a/compos/src/compilation.rs
+++ b/compos/src/compilation.rs
@@ -23,8 +23,11 @@
 
 use crate::fsverity;
 use authfs_aidl_interface::aidl::com::android::virt::fs::{
-    AuthFsConfig::AuthFsConfig, IAuthFs::IAuthFs, IAuthFsService::IAuthFsService,
-    InputFdAnnotation::InputFdAnnotation, OutputFdAnnotation::OutputFdAnnotation,
+    AuthFsConfig::{
+        AuthFsConfig, InputFdAnnotation::InputFdAnnotation, OutputFdAnnotation::OutputFdAnnotation,
+    },
+    IAuthFs::IAuthFs,
+    IAuthFsService::IAuthFsService,
 };
 use authfs_aidl_interface::binder::{ParcelFileDescriptor, Strong};
 use compos_aidl_interface::aidl::com::android::compos::FdAnnotation::FdAnnotation;
@@ -148,6 +151,8 @@
             .iter()
             .map(|fd| OutputFdAnnotation { fd: *fd })
             .collect(),
+        inputDirFdAnnotations: vec![],
+        outputDirFdAnnotations: vec![],
     }
 }