bin/vm run-microdroid supports --network-supported flag.

Bug: 340376951
Test: adb shell /apex/com.android.virt/bin/vm run-microdroid
--network-supported
Test: adb shell /apex/com.android.virt/bin/vm run-microdroid
--network-supported --protected

Change-Id: I1d88fe11d79b8ea46e12b6dfaab318aabdc0a2e0
diff --git a/apex/Android.bp b/apex/Android.bp
index 0eb8b9e..99b2dee 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -192,6 +192,9 @@
             androidManifest: "AndroidManifest.xml",
         },
         release_avf_enable_network: {
+            prebuilts: [
+                "com.android.virt.vmnic.rc",
+            ],
             arch: {
                 arm64: {
                     binaries: ["vmnic"],
@@ -256,14 +259,21 @@
     name: "com.android.virt.init.rc",
     src: ":virtualizationservice_rc_combined",
     filename: "virtualizationservice.rc",
-    installable: false,
+    no_full_install: true,
 }
 
 prebuilt_etc {
     name: "com.android.virt.vfio_handler.rc",
     src: "vfio_handler.rc",
     filename: "vfio_handler.rc",
-    installable: false,
+    no_full_install: true,
+}
+
+prebuilt_etc {
+    name: "com.android.virt.vmnic.rc",
+    src: "vmnic.rc",
+    filename: "vmnic.rc",
+    no_full_install: true,
 }
 
 // Virt apex needs a custom signer for its payload
diff --git a/virtualizationservice/vmnic/vmnic.rc b/apex/vmnic.rc
similarity index 100%
rename from virtualizationservice/vmnic/vmnic.rc
rename to apex/vmnic.rc
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 653281d..796ae21 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -14,7 +14,7 @@
 
 //! Implementation of the AIDL interface of the VirtualizationService.
 
-use crate::{get_calling_pid, get_calling_uid};
+use crate::{get_calling_pid, get_calling_uid, get_this_pid};
 use crate::atom::{write_vm_booted_stats, write_vm_creation_stats};
 use crate::composite::make_composite_image;
 use crate::crosvm::{CrosvmConfig, DiskFile, DisplayConfig, InputDeviceOption, PayloadState, VmContext, VmInstance, VmState};
@@ -606,6 +606,18 @@
             vec![]
         };
 
+        // Create TAP network interface if the VM supports network.
+        let _tap_fd = if cfg!(network) && config.networkSupported {
+            if *is_protected {
+                return Err(anyhow!("Network feature is not supported for pVM yet"))
+                    .with_log()
+                    .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION)?;
+            }
+            Some(GLOBAL_SERVICE.createTapInterface(&get_this_pid().to_string())?)
+        } else {
+            None
+        };
+
         // Actually start the VM.
         let crosvm_config = CrosvmConfig {
             cid,
@@ -913,6 +925,7 @@
         }
 
         vm_config.devices.clone_from(&custom_config.devices);
+        vm_config.networkSupported = custom_config.networkSupported;
     }
 
     if config.memoryMib > 0 {
diff --git a/virtualizationmanager/src/main.rs b/virtualizationmanager/src/main.rs
index a31fd0a..4e88507 100644
--- a/virtualizationmanager/src/main.rs
+++ b/virtualizationmanager/src/main.rs
@@ -39,10 +39,16 @@
 const LOG_TAG: &str = "virtmgr";
 
 lazy_static! {
+    static ref PID_CURRENT: Pid = Pid::this();
     static ref PID_PARENT: Pid = Pid::parent();
     static ref UID_CURRENT: Uid = Uid::current();
 }
 
+fn get_this_pid() -> pid_t {
+    // Return the process ID of this process.
+    PID_CURRENT.as_raw()
+}
+
 fn get_calling_pid() -> pid_t {
     // The caller is the parent of this process.
     PID_PARENT.as_raw()
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
index 9951bfd..a3f4b0f 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineAppConfig.aidl
@@ -124,6 +124,9 @@
          * should rarely need to be set false.
          */
         boolean wantUpdatable = true;
+
+        /** Whether the VM should have network feature. */
+        boolean networkSupported;
     }
 
     /** Configuration parameters guarded by android.permission.USE_CUSTOM_VIRTUAL_MACHINE */
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index cf9d25a..a5a849a 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -85,4 +85,7 @@
 
     /** List of input devices to the VM */
     InputDevice[] inputDevices;
+
+    /** Whether the VM should have network feature. */
+    boolean networkSupported;
 }
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
index 84f8734..4e6879d 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
@@ -121,4 +121,11 @@
     void setDisplayService(IBinder ibinder);
     void clearDisplayService();
     IBinder waitDisplayService();
+
+    /**
+     * Create TAP network interface for a VM.
+     * @param suffix of network interface name.
+     * @return file descriptor of the TAP network interface.
+     */
+    ParcelFileDescriptor createTapInterface(String ifaceNameSuffix);
 }
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVmnic.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVmnic.aidl
index 3796763..66739da 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVmnic.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVmnic.aidl
@@ -18,8 +18,8 @@
 interface IVmnic {
     /**
      * Create TAP network interface for a VM.
-     * @param CID of VM.
+     * @param suffix of network interface name.
      * @return file descriptor of the TAP network interface.
      */
-    ParcelFileDescriptor createTapInterface(int cid);
+    ParcelFileDescriptor createTapInterface(String ifaceNameSuffix);
 }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 1fa634d..5dbfe22 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -70,6 +70,7 @@
     IVfioHandler::VfioDev::VfioDev,
     IVfioHandler::{BpVfioHandler, IVfioHandler},
     IVirtualizationServiceInternal::IVirtualizationServiceInternal,
+    IVmnic::{BpVmnic, IVmnic},
 };
 use virtualmachineservice::IVirtualMachineService::VM_TOMBSTONES_SERVICE_PORT;
 use vsock::{VsockListener, VsockStream};
@@ -159,6 +160,9 @@
     static ref VFIO_SERVICE: Strong<dyn IVfioHandler> =
         wait_for_interface(<BpVfioHandler as IVfioHandler>::get_descriptor())
             .expect("Could not connect to VfioHandler");
+    static ref NETWORK_SERVICE: Strong<dyn IVmnic> =
+        wait_for_interface(<BpVmnic as IVmnic>::get_descriptor())
+            .expect("Could not connect to Vmnic");
 }
 
 fn is_valid_guest_cid(cid: Cid) -> bool {
@@ -494,6 +498,18 @@
         }
         Ok(())
     }
+
+    fn createTapInterface(&self, iface_name_suffix: &str) -> binder::Result<ParcelFileDescriptor> {
+        check_use_custom_virtual_machine()?;
+        if !cfg!(network) {
+            return Err(Status::new_exception_str(
+                ExceptionCode::UNSUPPORTED_OPERATION,
+                Some("createTapInterface is not supported with the network feature disabled"),
+            ))
+            .with_log();
+        }
+        NETWORK_SERVICE.createTapInterface(iface_name_suffix)
+    }
 }
 
 impl IVirtualizationMaintenance for VirtualizationServiceInternal {
diff --git a/virtualizationservice/vmnic/Android.bp b/virtualizationservice/vmnic/Android.bp
index 4313a82..784c648 100644
--- a/virtualizationservice/vmnic/Android.bp
+++ b/virtualizationservice/vmnic/Android.bp
@@ -17,5 +17,4 @@
         "liblog_rust",
     ],
     apex_available: ["com.android.virt"],
-    init_rc: ["vmnic.rc"],
 }
diff --git a/virtualizationservice/vmnic/src/aidl.rs b/virtualizationservice/vmnic/src/aidl.rs
index 26a0eff..6443258 100644
--- a/virtualizationservice/vmnic/src/aidl.rs
+++ b/virtualizationservice/vmnic/src/aidl.rs
@@ -17,6 +17,7 @@
 use anyhow::anyhow;
 use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::IVmnic::IVmnic;
 use binder::{self, ExceptionCode, Interface, IntoBinderResult, ParcelFileDescriptor};
+use log::info;
 
 #[derive(Debug, Default)]
 pub struct Vmnic {}
@@ -30,7 +31,10 @@
 impl Interface for Vmnic {}
 
 impl IVmnic for Vmnic {
-    fn createTapInterface(&self, _cid: i32) -> binder::Result<ParcelFileDescriptor> {
+    fn createTapInterface(&self, iface_name_suffix: &str) -> binder::Result<ParcelFileDescriptor> {
+        let ifname = format!("avf_tap_{iface_name_suffix}");
+        info!("Creating TAP interface {}", ifname);
+
         Err(anyhow!("Creating TAP network interface is not supported yet"))
             .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION)
     }
diff --git a/vm/src/main.rs b/vm/src/main.rs
index d6ee3a5..390a60d 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -60,6 +60,23 @@
     /// https://docs.kernel.org/admin-guide/mm/transhuge.html
     #[arg(short, long)]
     hugepages: bool,
+
+    /// Run VM with network feature.
+    #[cfg(network)]
+    #[arg(short, long)]
+    network_supported: bool,
+}
+
+impl CommonConfig {
+    #[cfg(network)]
+    fn network_supported(&self) -> bool {
+        self.network_supported
+    }
+
+    #[cfg(not(network))]
+    fn network_supported(&self) -> bool {
+        false
+    }
 }
 
 #[derive(Args, Default)]
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 5e797f8..0c9fbb6 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -159,6 +159,7 @@
                 x.to_str().map(String::from).ok_or(anyhow!("Failed to convert {x:?} to String"))
             })
             .collect::<Result<_, _>>()?,
+        networkSupported: config.common.network_supported(),
         ..Default::default()
     };