Merge "binder::get_interface -> binder::wait_for_interface" into main
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/docs/custom_vm.md b/docs/custom_vm.md
index 7b30835..0825f06 100644
--- a/docs/custom_vm.md
+++ b/docs/custom_vm.md
@@ -25,6 +25,35 @@
 The `vm` command also has other subcommands for debugging; run
 `/apex/com.android.virt/bin/vm help` for details.
 
+### Running Debian with u-boot
+1. Prepare u-boot binary from `u-boot_crosvm_aarch64` in https://ci.android.com/builds/branches/aosp_u-boot-mainline/grid
+or build it by https://source.android.com/docs/devices/cuttlefish/bootloader-dev#develop-bootloader
+2. Prepare Debian image from https://cloud.debian.org/images/cloud/ (We tested nocloud image)
+3. Copy `u-boot.bin`, Debian image file(like `debian-12-nocloud-arm64.raw`) and `vm_config.json` to `/data/local/tmp`
+```shell
+cat > vm_config.json <<EOF
+{
+    "name": "debian",
+    "bootloader": "/data/local/tmp/u-boot.bin",
+    "disks": [
+        {
+            "image": "/data/local/tmp/debian-12-nocloud-arm64.raw",
+            "partitions": [],
+            "writable": true
+        }
+    ],
+    "protected": false,
+    "cpu_topology": "match_host",
+    "platform_version": "~1.0",
+    "memory_mib" : 8096
+}
+EOF
+adb push `u-boot.bin` /data/local/tmp
+adb push `debian-12-nocloud-arm64.raw` /data/local/tmp
+adb push vm_config.json /data/local/tmp/vm_config.json
+```
+4. Launch VmLauncherApp(the detail will be explain below)
+
 ## Graphical VMs
 
 To run OSes with graphics support, follow the instruction below.
diff --git a/service_vm/README.md b/service_vm/README.md
index ca03c1d..b45b3ae 100644
--- a/service_vm/README.md
+++ b/service_vm/README.md
@@ -5,18 +5,35 @@
 following requirements:
 
 -   Only one instance of the Service VM is allowed to run at any given time.
--   The *secret* contained within the instance image of the Service VM remains
-    unchanged during updates of both the client VMs and the Service VM.
+-   The instance ID of the Service VM remains unchanged during updates of
+    both the client VMs and the Service VM.
 
-The secret is an encrypted random array that can only be decrypted by
-[pVM Firmware][pvmfw]. It is incorporated into the [CDI values][cdi] calculation
-of each VM loaded by pVM Firmware to ensure consistent CDI values for the VM
+The instance ID is incorporated into the [CDI values][cdi] calculation of
+each VM loaded by pVM Firmware to ensure consistent CDI values for the VM
 across all reboots.
 
 [cdi]: https://android.googlesource.com/platform/external/open-dice/+/main/docs/specification.md#CDI-Values
-[pvmfw]: https://android.googlesource.com/platform/packages/modules/Virtualization/+/main/pvmfw/README.md
 
-## RKP VM (Remote Key Provisioning Virtual Machine)
+## Architecture
+
+[Rialto](../rialto) is used as the bare-metal kernel for the Service VM. It
+shares some low-level setup, such as memory management and virtio device
+parsing, with pvmfw. The common setup code is grouped in [vmbase/](../vmbase).
+
+## Functionality
+
+The main functionality of the Service VM is to process requests from the host
+and provide responses for each request. The requests and responses are
+serialized in CBOR format and transmitted over a virtio-vsock device.
+
+-   [./comm](./comm) contains the definitions for the requests and responses.
+-   [./requests](./requests) contains the library that processes the requests.
+-   [./manager](./manager) manages the Service VM session, ensuring that only
+    one Service VM is active at any given time. The
+    [virtualizationservice](../virtualizationservice) process owns and manages
+    the Service VM instance.
+
+### RKP VM (Remote Key Provisioning Virtual Machine)
 
 Currently, the Service VM only supports VM remote attestation, and in that
 context we refer to it as the RKP VM. The RKP VM undergoes validation by the
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 941f38b..aeee6f7 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 7eb00e3..5e71245 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()
     };