Merge "[rkp] Retrieve attestation key from rkpd" into main
diff --git a/Android.bp b/Android.bp
index 550a6be..9c17c7f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -22,6 +22,7 @@
     module_type: "rust_defaults",
     config_namespace: "ANDROID",
     bool_variables: [
+        "release_avf_enable_device_assignment",
         "release_avf_enable_dice_changes",
         "release_avf_enable_llpvm_changes",
         "release_avf_enable_multi_tenant_microdroid_vm",
@@ -36,6 +37,9 @@
 avf_flag_aware_rust_defaults {
     name: "avf_build_flags_rust",
     soong_config_variables: {
+        release_avf_enable_device_assignment: {
+            cfgs: ["device_assignment"],
+        },
         release_avf_enable_dice_changes: {
             cfgs: ["dice_changes"],
         },
diff --git a/apex/Android.bp b/apex/Android.bp
index a4c8861..e04dbd2 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -67,7 +67,21 @@
     ],
 }
 
-apex_defaults {
+soong_config_module_type {
+    name: "avf_flag_aware_apex_defaults",
+    module_type: "apex_defaults",
+    config_namespace: "ANDROID",
+    bool_variables: [
+        "release_avf_enable_device_assignment",
+        "release_avf_enable_vendor_modules",
+    ],
+    properties: [
+        "arch",
+        "prebuilts",
+    ],
+}
+
+avf_flag_aware_apex_defaults {
     name: "com.android.virt_avf_enabled",
 
     defaults: ["com.android.virt_common"],
@@ -79,7 +93,6 @@
         arm64: {
             binaries: [
                 "crosvm",
-                "vfio_handler",
                 "virtmgr",
                 "virtualizationservice",
             ],
@@ -88,7 +101,6 @@
         x86_64: {
             binaries: [
                 "crosvm",
-                "vfio_handler",
                 "virtmgr",
                 "virtualizationservice",
             ],
@@ -115,6 +127,29 @@
     apps: [
         "EmptyPayloadApp",
     ],
+    soong_config_variables: {
+        release_avf_enable_device_assignment: {
+            prebuilts: [
+                "com.android.virt.vfio_handler.rc",
+            ],
+            arch: {
+                arm64: {
+                    binaries: ["vfio_handler"],
+                },
+                x86_64: {
+                    binaries: ["vfio_handler"],
+                },
+            },
+        },
+        release_avf_enable_vendor_modules: {
+            prebuilts: [
+                "microdroid_gki_initrd_debuggable",
+                "microdroid_gki_initrd_normal",
+                "microdroid_gki_kernel",
+                "microdroid_gki.json",
+            ],
+        },
+    },
 }
 
 apex_defaults {
@@ -141,6 +176,13 @@
     installable: false,
 }
 
+prebuilt_etc {
+    name: "com.android.virt.vfio_handler.rc",
+    src: "vfio_handler.rc",
+    filename: "vfio_handler.rc",
+    installable: false,
+}
+
 sh_binary_host {
     name: "prepare_device_vfio",
     src: "prepare_device_vfio.sh",
diff --git a/apex/sign_virt_apex.py b/apex/sign_virt_apex.py
index 029ac76..7393636 100644
--- a/apex/sign_virt_apex.py
+++ b/apex/sign_virt_apex.py
@@ -413,10 +413,13 @@
 # dict of (key, file) for re-sign/verification. keys are un-versioned for readability.
 virt_apex_files = {
     'kernel': 'etc/fs/microdroid_kernel',
+    'gki_kernel': 'etc/fs/microdroid_gki_kernel',
     'vbmeta.img': 'etc/fs/microdroid_vbmeta.img',
     'super.img': 'etc/fs/microdroid_super.img',
     'initrd_normal.img': 'etc/microdroid_initrd_normal.img',
+    'gki_initrd_normal.img': 'etc/microdroid_gki_initrd_normal.img',
     'initrd_debuggable.img': 'etc/microdroid_initrd_debuggable.img',
+    'gki_initrd_debuggable.img': 'etc/microdroid_gki_initrd_debuggable.img',
 }
 
 
@@ -458,26 +461,40 @@
                      images=images,
                      wait=images_f)
 
+    has_gki_kernel = os.path.isfile(files['gki_kernel'])
+
     vbmeta_bc_f = None
     if not args.do_not_update_bootconfigs:
-        vbmeta_bc_f = Async(UpdateVbmetaBootconfig, args,
-                            [files['initrd_normal.img'],
-                                files['initrd_debuggable.img']], files['vbmeta.img'],
+        initrd_files = [files['initrd_normal.img'], files['initrd_debuggable.img']]
+        if has_gki_kernel:
+            initrd_files += [files['gki_initrd_normal.img'], files['gki_initrd_debuggable.img']]
+        vbmeta_bc_f = Async(UpdateVbmetaBootconfig, args, initrd_files,
+                            files['vbmeta.img'],
                             wait=[vbmeta_f])
 
     # Re-sign kernel. Note kernel's vbmeta contain addition descriptor from ramdisk(s)
-    initrd_normal_hashdesc = tempfile.NamedTemporaryFile(delete=False).name
-    initrd_debug_hashdesc = tempfile.NamedTemporaryFile(delete=False).name
-    initrd_n_f = Async(GenVbmetaImage, args, files['initrd_normal.img'],
-                       initrd_normal_hashdesc, "initrd_normal",
-                       wait=[vbmeta_bc_f] if vbmeta_bc_f is not None else [])
-    initrd_d_f = Async(GenVbmetaImage, args, files['initrd_debuggable.img'],
-                       initrd_debug_hashdesc, "initrd_debug",
-                       wait=[vbmeta_bc_f] if vbmeta_bc_f is not None else [])
-    Async(AddHashFooter, args, key, files['kernel'], partition_name="boot",
-          additional_descriptors=[
-              initrd_normal_hashdesc, initrd_debug_hashdesc],
-          wait=[initrd_n_f, initrd_d_f])
+    def resign_kernel(kernel, initrd_normal, initrd_debug):
+        kernel_file = files[kernel]
+        initrd_normal_file = files[initrd_normal]
+        initrd_debug_file = files[initrd_debug]
+
+        initrd_normal_hashdesc = tempfile.NamedTemporaryFile(delete=False).name
+        initrd_debug_hashdesc = tempfile.NamedTemporaryFile(delete=False).name
+        initrd_n_f = Async(GenVbmetaImage, args, initrd_normal_file,
+                           initrd_normal_hashdesc, "initrd_normal",
+                           wait=[vbmeta_bc_f] if vbmeta_bc_f is not None else [])
+        initrd_d_f = Async(GenVbmetaImage, args, initrd_debug_file,
+                           initrd_debug_hashdesc, "initrd_debug",
+                           wait=[vbmeta_bc_f] if vbmeta_bc_f is not None else [])
+        Async(AddHashFooter, args, key, kernel_file, partition_name="boot",
+              additional_descriptors=[
+                  initrd_normal_hashdesc, initrd_debug_hashdesc],
+              wait=[initrd_n_f, initrd_d_f])
+
+    resign_kernel('kernel', 'initrd_normal.img', 'initrd_debuggable.img')
+
+    if has_gki_kernel:
+        resign_kernel('gki_kernel', 'gki_initrd_normal.img', 'gki_initrd_debuggable.img')
 
 
 def VerifyVirtApex(args):
@@ -502,7 +519,8 @@
         assert info['Public key (sha1)'] == pubkey_digest, f'pubkey mismatch: {file}'
 
     for f in files.values():
-        if f in (files['initrd_normal.img'], files['initrd_debuggable.img']):
+        if f in (files['initrd_normal.img'], files['initrd_debuggable.img'],
+                 files['gki_initrd_normal.img'], files['gki_initrd_debuggable.img']):
             # TODO(b/245277660): Verify that ramdisks contain the correct vbmeta digest
             continue
         if f == files['super.img']:
diff --git a/apex/vfio_handler.rc b/apex/vfio_handler.rc
new file mode 100644
index 0000000..419acef
--- /dev/null
+++ b/apex/vfio_handler.rc
@@ -0,0 +1,20 @@
+# Copyright (C) 2023 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.
+
+service vfio_handler /apex/com.android.virt/bin/vfio_handler
+    user root
+    group system
+    interface aidl android.system.virtualizationservice_internal.IVfioHandler
+    disabled
+    oneshot
diff --git a/apex/virtualizationservice.rc b/apex/virtualizationservice.rc
index 8283594..02b2081 100644
--- a/apex/virtualizationservice.rc
+++ b/apex/virtualizationservice.rc
@@ -19,10 +19,3 @@
     interface aidl android.system.virtualizationservice
     disabled
     oneshot
-
-service vfio_handler /apex/com.android.virt/bin/vfio_handler
-    user root
-    group system
-    interface aidl android.system.virtualizationservice_internal.IVfioHandler
-    disabled
-    oneshot
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index b369390..0bacdde 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -526,7 +526,7 @@
 
 /// Phandle of a FDT node
 #[repr(transparent)]
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
 pub struct Phandle(u32);
 
 impl Phandle {
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 4e735e6..23eadcf 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -330,6 +330,22 @@
     ],
 }
 
+android_filesystem {
+    name: "microdroid_gki_modules-6.1-arm64",
+    deps: [
+        "microdroid_gki_kernel_modules-6.1-arm64",
+    ],
+    type: "compressed_cpio",
+}
+
+android_filesystem {
+    name: "microdroid_gki_modules-6.1-x86_64",
+    deps: [
+        "microdroid_gki_kernel_modules-6.1-x86_64",
+    ],
+    type: "compressed_cpio",
+}
+
 genrule {
     name: "microdroid_bootconfig_arm64_gen",
     srcs: [
@@ -400,6 +416,11 @@
 }
 
 prebuilt_etc {
+    name: "microdroid_gki.json",
+    src: "microdroid_gki.json",
+}
+
+prebuilt_etc {
     name: "microdroid_manifest",
     src: "microdroid_manifest.xml",
     filename: "manifest.xml",
@@ -444,6 +465,23 @@
     },
 }
 
+avb_gen_vbmeta_image {
+    name: "microdroid_gki_initrd_normal_hashdesc",
+    src: ":microdroid_gki_initrd_normal",
+    partition_name: "initrd_normal",
+    salt: initrd_normal_salt,
+    enabled: false,
+    arch: {
+        // Microdroid kernel is only available in these architectures.
+        arm64: {
+            enabled: true,
+        },
+        x86_64: {
+            enabled: true,
+        },
+    },
+}
+
 // python -c "import hashlib; print(hashlib.sha256(b'initrd_debug').hexdigest())"
 initrd_debug_salt = "8ab9dc9cb7e6456700ff6ef18c6b4c3acc24c5fa5381b829563f8d7a415d869a"
 
@@ -464,6 +502,23 @@
     },
 }
 
+avb_gen_vbmeta_image {
+    name: "microdroid_gki_initrd_debug_hashdesc",
+    src: ":microdroid_gki_initrd_debuggable",
+    partition_name: "initrd_debug",
+    salt: initrd_debug_salt,
+    enabled: false,
+    arch: {
+        // Microdroid kernel is only available in these architectures.
+        arm64: {
+            enabled: true,
+        },
+        x86_64: {
+            enabled: true,
+        },
+    },
+}
+
 soong_config_module_type {
     name: "flag_aware_avb_add_hash_footer",
     module_type: "avb_add_hash_footer",
@@ -513,6 +568,42 @@
     },
 }
 
+flag_aware_avb_add_hash_footer {
+    name: "microdroid_gki_kernel_signed",
+    src: ":empty_file",
+    filename: "microdroid_gki_kernel",
+    partition_name: "boot",
+    private_key: ":microdroid_sign_key",
+    salt: bootloader_salt,
+    enabled: false,
+    arch: {
+        arm64: {
+            src: ":microdroid_gki_kernel_prebuilts-6.1-arm64",
+            enabled: true,
+        },
+        x86_64: {
+            src: ":microdroid_gki_kernel_prebuilts-6.1-x86_64",
+            enabled: true,
+        },
+    },
+    include_descriptors_from_images: [
+        ":microdroid_gki_initrd_normal_hashdesc",
+        ":microdroid_gki_initrd_debug_hashdesc",
+    ],
+    // Below are properties that are conditionally set depending on value of build flags.
+    soong_config_variables: {
+        release_avf_enable_llpvm_changes: {
+            rollback_index: 1,
+            props: [
+                {
+                    name: "com.android.virt.cap",
+                    value: "secretkeeper_protection",
+                },
+            ],
+        },
+    },
+}
+
 prebuilt_etc {
     name: "microdroid_kernel",
     src: ":empty_file",
@@ -526,3 +617,17 @@
         },
     },
 }
+
+prebuilt_etc {
+    name: "microdroid_gki_kernel",
+    src: ":empty_file",
+    relative_install_path: "fs",
+    arch: {
+        arm64: {
+            src: ":microdroid_gki_kernel_signed",
+        },
+        x86_64: {
+            src: ":microdroid_gki_kernel_signed",
+        },
+    },
+}
diff --git a/microdroid/initrd/Android.bp b/microdroid/initrd/Android.bp
index de28d8a..6cd84fa 100644
--- a/microdroid/initrd/Android.bp
+++ b/microdroid/initrd/Android.bp
@@ -40,6 +40,28 @@
     cmd: "cat $(in) > $(out)",
 }
 
+genrule {
+    name: "microdroid_gki_initrd_gen_arm64",
+    srcs: [
+        ":microdroid_ramdisk",
+        ":microdroid_fstab_ramdisk",
+        ":microdroid_gki_modules-6.1-arm64",
+    ],
+    out: ["microdroid_initrd.img"],
+    cmd: "cat $(in) > $(out)",
+}
+
+genrule {
+    name: "microdroid_gki_initrd_gen_x86_64",
+    srcs: [
+        ":microdroid_ramdisk",
+        ":microdroid_fstab_ramdisk",
+        ":microdroid_gki_modules-6.1-x86_64",
+    ],
+    out: ["microdroid_initrd.img"],
+    cmd: "cat $(in) > $(out)",
+}
+
 // This contains vbmeta hashes & related (boot)configs which are passed to kernel/init
 genrule {
     name: "microdroid_vbmeta_bootconfig_gen",
@@ -74,6 +96,17 @@
 }
 
 genrule {
+    name: "microdroid_gki_initrd_debuggable_arm64",
+    tools: ["initrd_bootconfig"],
+    srcs: [
+        ":microdroid_gki_initrd_gen_arm64",
+        ":microdroid_bootconfig_debuggable_src",
+    ] + bootconfigs_arm64,
+    out: ["microdroid_gki_initrd_debuggable_arm64"],
+    cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
+}
+
+genrule {
     name: "microdroid_initrd_debuggable_x86_64",
     tools: ["initrd_bootconfig"],
     srcs: [
@@ -85,6 +118,17 @@
 }
 
 genrule {
+    name: "microdroid_gki_initrd_debuggable_x86_64",
+    tools: ["initrd_bootconfig"],
+    srcs: [
+        ":microdroid_gki_initrd_gen_x86_64",
+        ":microdroid_bootconfig_debuggable_src",
+    ] + bootconfigs_x86_64,
+    out: ["microdroid_gki_initrd_debuggable_x86_64"],
+    cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
+}
+
+genrule {
     name: "microdroid_initrd_normal_arm64",
     tools: ["initrd_bootconfig"],
     srcs: [
@@ -96,6 +140,17 @@
 }
 
 genrule {
+    name: "microdroid_gki_initrd_normal_arm64",
+    tools: ["initrd_bootconfig"],
+    srcs: [
+        ":microdroid_gki_initrd_gen_arm64",
+        ":microdroid_bootconfig_normal_src",
+    ] + bootconfigs_arm64,
+    out: ["microdroid_gki_initrd_normal_arm64"],
+    cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
+}
+
+genrule {
     name: "microdroid_initrd_normal_x86_64",
     tools: ["initrd_bootconfig"],
     srcs: [
@@ -106,6 +161,17 @@
     cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
 }
 
+genrule {
+    name: "microdroid_gki_initrd_normal_x86_64",
+    tools: ["initrd_bootconfig"],
+    srcs: [
+        ":microdroid_gki_initrd_gen_x86_64",
+        ":microdroid_bootconfig_normal_src",
+    ] + bootconfigs_x86_64,
+    out: ["microdroid_gki_initrd_normal_x86_64"],
+    cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
+}
+
 prebuilt_etc {
     name: "microdroid_initrd_debuggable",
     // We don't have ramdisk for architectures other than x86_64 & arm64
@@ -122,6 +188,21 @@
 }
 
 prebuilt_etc {
+    name: "microdroid_gki_initrd_debuggable",
+    // We don't have ramdisk for architectures other than x86_64 & arm64
+    src: ":empty_file",
+    arch: {
+        x86_64: {
+            src: ":microdroid_gki_initrd_debuggable_x86_64",
+        },
+        arm64: {
+            src: ":microdroid_gki_initrd_debuggable_arm64",
+        },
+    },
+    filename: "microdroid_gki_initrd_debuggable.img",
+}
+
+prebuilt_etc {
     name: "microdroid_initrd_normal",
     // We don't have ramdisk for architectures other than x86_64 & arm64
     src: ":empty_file",
@@ -135,3 +216,18 @@
     },
     filename: "microdroid_initrd_normal.img",
 }
+
+prebuilt_etc {
+    name: "microdroid_gki_initrd_normal",
+    // We don't have ramdisk for architectures other than x86_64 & arm64
+    src: ":empty_file",
+    arch: {
+        x86_64: {
+            src: ":microdroid_gki_initrd_normal_x86_64",
+        },
+        arm64: {
+            src: ":microdroid_gki_initrd_normal_arm64",
+        },
+    },
+    filename: "microdroid_gki_initrd_normal.img",
+}
diff --git a/microdroid/microdroid_gki.json b/microdroid/microdroid_gki.json
new file mode 100644
index 0000000..d7ba53e
--- /dev/null
+++ b/microdroid/microdroid_gki.json
@@ -0,0 +1,20 @@
+{
+  "kernel": "/apex/com.android.virt/etc/fs/microdroid_gki_kernel",
+  "disks": [
+    {
+      "partitions": [
+        {
+          "label": "vbmeta_a",
+          "path": "/apex/com.android.virt/etc/fs/microdroid_vbmeta.img"
+        },
+        {
+          "label": "super",
+          "path": "/apex/com.android.virt/etc/fs/microdroid_super.img"
+        }
+      ],
+      "writable": false
+    }
+  ],
+  "memory_mib": 256,
+  "platform_version": "~1.0"
+}
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index f335297..6ae3bbd 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -101,6 +101,8 @@
 
 const MICRODROID_OS_NAME: &str = "microdroid";
 
+const MICRODROID_GKI_OS_NAME: &str = "microdroid_gki";
+
 const UNFORMATTED_STORAGE_MAGIC: &str = "UNFORMATTED-STORAGE";
 
 /// Roughly estimated sufficient size for storing vendor public key into DTBO.
@@ -694,6 +696,16 @@
     }
 }
 
+fn is_valid_os(os_name: &str) -> bool {
+    if os_name == MICRODROID_OS_NAME {
+        return true;
+    }
+    if cfg!(vendor_modules) && os_name == MICRODROID_GKI_OS_NAME {
+        return true;
+    }
+    false
+}
+
 fn load_app_config(
     config: &VirtualMachineAppConfig,
     debug_config: &DebugConfig,
@@ -717,9 +729,9 @@
         Payload::PayloadConfig(payload_config) => create_vm_payload_config(payload_config)?,
     };
 
-    // For now, the only supported OS is Microdroid
+    // For now, the only supported OS is Microdroid and Microdroid GKI
     let os_name = vm_payload_config.os.name.as_str();
-    if os_name != MICRODROID_OS_NAME {
+    if !is_valid_os(os_name) {
         bail!("Unknown OS \"{}\"", os_name);
     }
 
@@ -753,7 +765,7 @@
     vm_config.cpuTopology = config.cpuTopology;
 
     // Microdroid takes additional init ramdisk & (optionally) storage image
-    add_microdroid_system_images(config, instance_file, storage_image, &mut vm_config)?;
+    add_microdroid_system_images(config, instance_file, storage_image, os_name, &mut vm_config)?;
 
     // Include Microdroid payload disk (contains apks, idsigs) in vm config
     add_microdroid_payload_images(
@@ -788,8 +800,9 @@
     }
 
     let task = Task { type_: TaskType::MicrodroidLauncher, command: payload_binary_name.clone() };
+    let name = payload_config.osName.clone();
     Ok(VmPayloadConfig {
-        os: OsConfig { name: MICRODROID_OS_NAME.to_owned() },
+        os: OsConfig { name },
         task: Some(task),
         apexes: vec![],
         extra_apks: vec![],
@@ -871,7 +884,7 @@
 /// Check that a file SELinux label is acceptable.
 ///
 /// We only want to allow code in a VM to be sourced from places that apps, and the
-/// system, do not have write access to.
+/// system or vendor, do not have write access to.
 ///
 /// Note that sepolicy must also grant read access for these types to both virtualization
 /// service and crosvm.
@@ -885,6 +898,7 @@
         | "staging_data_file" // updated/staged APEX images
         | "system_file" // immutable dm-verity protected partition
         | "virtualizationservice_data_file" // files created by VS / VirtMgr
+        | "vendor_microdroid_file" // immutable dm-verity protected partition (/vendor/etc/avf/microdroid/.*)
          => Ok(()),
         _ => bail!("Label {} is not allowed", context),
     }
@@ -1195,10 +1209,24 @@
     Ok(())
 }
 
+fn check_no_devices(config: &VirtualMachineConfig) -> binder::Result<()> {
+    let VirtualMachineConfig::AppConfig(config) = config else { return Ok(()) };
+    if let Some(custom_config) = &config.customConfig {
+        if !custom_config.devices.is_empty() {
+            return Err(anyhow!("device assignment feature is disabled"))
+                .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
+        }
+    }
+    Ok(())
+}
+
 fn check_config_features(config: &VirtualMachineConfig) -> binder::Result<()> {
     if !cfg!(vendor_modules) {
         check_no_vendor_modules(config)?;
     }
+    if !cfg!(device_assignment) {
+        check_no_devices(config)?;
+    }
     Ok(())
 }
 
diff --git a/virtualizationmanager/src/payload.rs b/virtualizationmanager/src/payload.rs
index 3bfad33..c19c103 100644
--- a/virtualizationmanager/src/payload.rs
+++ b/virtualizationmanager/src/payload.rs
@@ -425,6 +425,7 @@
     config: &VirtualMachineAppConfig,
     instance_file: File,
     storage_image: Option<File>,
+    os_name: &str,
     vm_config: &mut VirtualMachineRawConfig,
 ) -> Result<()> {
     let debug_suffix = match config.debugLevel {
@@ -432,7 +433,7 @@
         DebugLevel::FULL => "debuggable",
         _ => return Err(anyhow!("unsupported debug level: {:?}", config.debugLevel)),
     };
-    let initrd = format!("/apex/com.android.virt/etc/microdroid_initrd_{}.img", debug_suffix);
+    let initrd = format!("/apex/com.android.virt/etc/{os_name}_initrd_{debug_suffix}.img");
     vm_config.initrd = Some(open_parcel_file(Path::new(&initrd), false)?);
 
     let mut writable_partitions = vec![Partition {
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
index 55c2f5d..f3f54f3 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachinePayloadConfig.aidl
@@ -23,4 +23,9 @@
      * function invoked.
      */
     @utf8InCpp String payloadBinaryName;
+
+    /**
+     * Name of the OS to run the payload. Currently "microdroid" and "microdroid_gki" is supported.
+     */
+    @utf8InCpp String osName = "microdroid";
 }
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 0af9791..87278bc 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -97,33 +97,24 @@
     #[arg(long)]
     storage_size: Option<u64>,
 
-    /// Path to custom kernel image to use when booting Microdroid.
-    #[cfg(vendor_modules)]
-    #[arg(long)]
-    kernel: Option<PathBuf>,
-
     /// Path to disk image containing vendor-specific modules.
     #[cfg(vendor_modules)]
     #[arg(long)]
     vendor: Option<PathBuf>,
 
     /// SysFS nodes of devices to assign to VM
+    #[cfg(device_assignment)]
     #[arg(long)]
     devices: Vec<PathBuf>,
+
+    /// If set, use GKI instead of microdroid kernel
+    #[cfg(vendor_modules)]
+    #[arg(long)]
+    gki: bool,
 }
 
 impl MicrodroidConfig {
     #[cfg(vendor_modules)]
-    fn kernel(&self) -> &Option<PathBuf> {
-        &self.kernel
-    }
-
-    #[cfg(not(vendor_modules))]
-    fn kernel(&self) -> Option<PathBuf> {
-        None
-    }
-
-    #[cfg(vendor_modules)]
     fn vendor(&self) -> &Option<PathBuf> {
         &self.vendor
     }
@@ -132,6 +123,26 @@
     fn vendor(&self) -> Option<PathBuf> {
         None
     }
+
+    #[cfg(vendor_modules)]
+    fn gki(&self) -> bool {
+        self.gki
+    }
+
+    #[cfg(not(vendor_modules))]
+    fn gki(&self) -> bool {
+        false
+    }
+
+    #[cfg(device_assignment)]
+    fn devices(&self) -> &Vec<PathBuf> {
+        &self.devices
+    }
+
+    #[cfg(not(device_assignment))]
+    fn devices(&self) -> Vec<PathBuf> {
+        Vec::new()
+    }
 }
 
 #[derive(Args)]
diff --git a/vm/src/run.rs b/vm/src/run.rs
index 1ba9dec..44ba9af 100644
--- a/vm/src/run.rs
+++ b/vm/src/run.rs
@@ -98,9 +98,6 @@
         None
     };
 
-    let kernel =
-        config.microdroid.kernel().as_ref().map(|p| open_parcel_file(p, false)).transpose()?;
-
     let vendor =
         config.microdroid.vendor().as_ref().map(|p| open_parcel_file(p, false)).transpose()?;
 
@@ -114,8 +111,11 @@
         }
         Payload::ConfigPath(config_path)
     } else if let Some(payload_binary_name) = config.payload_binary_name {
+        let os_name =
+            if config.microdroid.gki() { "microdroid_gki" } else { "microdroid" }.to_owned();
         Payload::PayloadConfig(VirtualMachinePayloadConfig {
             payloadBinaryName: payload_binary_name,
+            osName: os_name,
         })
     } else {
         bail!("Either --config-path or --payload-binary-name must be defined")
@@ -124,13 +124,13 @@
     let payload_config_str = format!("{:?}!{:?}", config.apk, payload);
 
     let custom_config = CustomConfig {
-        customKernelImage: kernel,
+        customKernelImage: None,
         gdbPort: config.debug.gdb.map(u16::from).unwrap_or(0) as i32, // 0 means no gdb
         taskProfiles: config.common.task_profiles,
         vendorImage: vendor,
         devices: config
             .microdroid
-            .devices
+            .devices()
             .iter()
             .map(|x| {
                 x.to_str().map(String::from).ok_or(anyhow!("Failed to convert {x:?} to String"))