Merge "microdroid_manager uses kernlog"
diff --git a/apex/Android.bp b/apex/Android.bp
index 2194c67..c06740a 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -7,6 +7,7 @@
 
     // TODO(jiyong): make it updatable
     updatable: false,
+    platform_apis: true,
 
     manifest: "manifest.json",
 
diff --git a/compos/apex/Android.bp b/compos/apex/Android.bp
index 95463d0..9942e09 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -34,6 +34,7 @@
 
     // TODO(victorhsieh): make it updatable
     updatable: false,
+    platform_apis: true,
 
     binaries: [
         "compos_key_service",
diff --git a/microdroid/sepolicy/system/private/domain.te b/microdroid/sepolicy/system/private/domain.te
index 4a59f73..e979f3e 100644
--- a/microdroid/sepolicy/system/private/domain.te
+++ b/microdroid/sepolicy/system/private/domain.te
@@ -216,7 +216,7 @@
     -appdomain # for oemfs
     -bootanim # for oemfs
     -recovery # for /tmp/update_binary in tmpfs
-    -microdroid_launcher -microdroid_manager # for executing shared libs on /mnt/apk in Microdroid
+    -microdroid_app -microdroid_manager # for executing shared libs on /mnt/apk in Microdroid
 } { fs_type -rootfs }:file execute;
 
 #
diff --git a/microdroid/sepolicy/system/private/file_contexts b/microdroid/sepolicy/system/private/file_contexts
index 7e6048e..4318bb0 100644
--- a/microdroid/sepolicy/system/private/file_contexts
+++ b/microdroid/sepolicy/system/private/file_contexts
@@ -114,7 +114,7 @@
 /system/bin/toolbox	--	u:object_r:toolbox_exec:s0
 /system/bin/toybox	--	u:object_r:toolbox_exec:s0
 /system/bin/zipfuse              u:object_r:zipfuse_exec:s0
-/system/bin/microdroid_launcher  u:object_r:microdroid_launcher_exec:s0
+/system/bin/microdroid_launcher  u:object_r:microdroid_app_exec:s0
 /system/bin/microdroid_manager   u:object_r:microdroid_manager_exec:s0
 /system/bin/apkdmverity          u:object_r:apkdmverity_exec:s0
 /system/etc/cgroups\.json               u:object_r:cgroup_desc_file:s0
diff --git a/microdroid/sepolicy/system/private/microdroid_app.te b/microdroid/sepolicy/system/private/microdroid_app.te
new file mode 100644
index 0000000..eff9120
--- /dev/null
+++ b/microdroid/sepolicy/system/private/microdroid_app.te
@@ -0,0 +1,45 @@
+# microdroid_app is a domain for microdroid_launcher, which is a binary that
+# loads a shared library from an apk and executes it by calling an entry point
+# in the library. This can be considered as the native counterpart of
+# app_process for Java.
+#
+# Both microdroid_launcher and payload from the shared library run in the
+# context of microdroid_app.
+
+type microdroid_app, domain, coredomain;
+type microdroid_app_exec, exec_type, file_type, system_file_type;
+
+# Allow to communicate use, read and write over the adb connection.
+allow microdroid_app adbd:fd use;
+allow microdroid_app adbd:unix_stream_socket { read write };
+
+# microdroid_launcher is launched by microdroid_manager with fork/execvp.
+allow microdroid_app microdroid_manager:fd use;
+
+# Allow to use FDs inherited from the shell. This includes the FD opened for
+# the microdroid_launcher executable itself and the FD for adb connection.
+# TODO(b/186396070) remove this when this is executed from microdroid_manager
+userdebug_or_eng(`
+  allow microdroid_app shell:fd use;
+')
+
+# Allow to use terminal
+allow microdroid_app devpts:chr_file rw_file_perms;
+
+# Allow to set debug prop
+set_prop(microdroid_app, debug_prop)
+
+# Talk to binder services (for keystore)
+binder_use(microdroid_app);
+
+# Allow payloads to use keystore
+use_keystore(microdroid_app);
+
+# Allow payloads to use and manage their keys
+allow microdroid_app vm_payload_key:keystore2_key {
+    delete
+    get_info
+    manage_blob
+    rebind
+    use
+};
diff --git a/microdroid/sepolicy/system/private/microdroid_launcher.te b/microdroid/sepolicy/system/private/microdroid_launcher.te
deleted file mode 100644
index 6bcd4f1..0000000
--- a/microdroid/sepolicy/system/private/microdroid_launcher.te
+++ /dev/null
@@ -1,41 +0,0 @@
-# microdroid_launcher is a binary that loads a shared library from an apk and
-# executes it by calling an entry point in the library. This can be considered
-# as the native counterpart of app_process for Java.
-
-type microdroid_launcher, domain, coredomain;
-type microdroid_launcher_exec, exec_type, file_type, system_file_type;
-
-# Allow to communicate use, read and write over the adb connection.
-allow microdroid_launcher adbd:fd use;
-allow microdroid_launcher adbd:unix_stream_socket { read write };
-
-# microdroid_launcher is launched by microdroid_manager with fork/execvp.
-allow microdroid_launcher microdroid_manager:fd use;
-
-# Allow to use FDs inherited from the shell. This includes the FD opened for
-# the microdroid_launcher executable itself and the FD for adb connection.
-# TODO(b/186396070) remove this when this is executed from microdroid_manager
-userdebug_or_eng(`
-  allow microdroid_launcher shell:fd use;
-')
-
-# Allow to use terminal
-allow microdroid_launcher devpts:chr_file rw_file_perms;
-
-# Allow to set debug prop
-set_prop(microdroid_launcher, debug_prop)
-
-# Talk to binder services (for keystore)
-binder_use(microdroid_launcher);
-
-# Allow payloads to use keystore
-use_keystore(microdroid_launcher);
-
-# Allow payloads to use and manage their keys
-allow microdroid_launcher vm_payload_key:keystore2_key {
-    delete
-    get_info
-    manage_blob
-    rebind
-    use
-};
diff --git a/microdroid/sepolicy/system/private/microdroid_manager.te b/microdroid/sepolicy/system/private/microdroid_manager.te
index 579a7d4..81a6839 100644
--- a/microdroid/sepolicy/system/private/microdroid_manager.te
+++ b/microdroid/sepolicy/system/private/microdroid_manager.te
@@ -13,7 +13,7 @@
 allow microdroid_manager vd_device:blk_file r_file_perms;
 
 # microdroid_manager start payload task via microdroid_launcher
-domain_auto_trans(microdroid_manager, microdroid_launcher_exec, microdroid_launcher);
+domain_auto_trans(microdroid_manager, microdroid_app_exec, microdroid_app);
 
 # Let microdroid_manager exec other files (e.g. payload command) in the same domain.
 # TODO(b/189706019) we need to a domain for the app process.
diff --git a/microdroid/sepolicy/system/private/shell.te b/microdroid/sepolicy/system/private/shell.te
index 7c786c9..03490b0 100644
--- a/microdroid/sepolicy/system/private/shell.te
+++ b/microdroid/sepolicy/system/private/shell.te
@@ -193,7 +193,7 @@
 
 # Allow shell to launch microdroid_launcher in its own domain
 # TODO(b/186396070) remove this when microdroid_manager can do this
-domain_auto_trans(shell, microdroid_launcher_exec, microdroid_launcher)
+domain_auto_trans(shell, microdroid_app_exec, microdroid_app)
 domain_auto_trans(shell, microdroid_manager_exec, microdroid_manager)
 
 # Never allow others to set or get the perf.drop_caches property.
diff --git a/tests/Android.bp b/tests/Android.bp
index be6e653..8cfefcc 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -29,6 +29,7 @@
         "vsock_test.cc",
     ],
     local_include_dirs: ["include"],
+    compile_multilib: "64",
     data: [
         ":virt_test_kernel",
         ":virt_test_initramfs",
diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml
index f170f48..b56c0e8 100644
--- a/tests/AndroidTest.xml
+++ b/tests/AndroidTest.xml
@@ -19,19 +19,6 @@
       a test-only permission, run it without selinux -->
     <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer"/>
 
-    <!-- Basic checks that the device has all the prerequisites. -->
-    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
-        <option name="throw-if-cmd-fail" value="true" />
-        <!-- Kernel has KVM enabled. -->
-        <option name="run-command" value="ls /dev/kvm" />
-        <!-- Kernel has vhost-vsock enabled. -->
-        <option name="run-command" value="ls /dev/vhost-vsock" />
-        <!-- CrosVM is installed. -->
-        <option name="run-command" value="ls /apex/com.android.virt/bin/crosvm" />
-        <!-- VirtualizationService is installed. -->
-        <option name="run-command" value="ls /apex/com.android.virt/bin/virtualizationservice" />
-    </target_preparer>
-
     <!-- Push test binaries to the device. -->
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
diff --git a/tests/vsock_test.cc b/tests/vsock_test.cc
index 84827d8..233c6dd 100644
--- a/tests/vsock_test.cc
+++ b/tests/vsock_test.cc
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <unistd.h>
 
 // Needs to be included after sys/socket.h
 #include <linux/vm_sockets.h>
 
+#include <algorithm>
+#include <array>
 #include <iostream>
 #include <optional>
 
@@ -30,6 +34,8 @@
 #include "android/system/virtualizationservice/VirtualMachineConfig.h"
 #include "virt/VirtualizationTest.h"
 
+#define KVM_CAP_ARM_PROTECTED_VM 0xffbadab1
+
 using namespace android::base;
 using namespace android::os;
 
@@ -41,7 +47,24 @@
 static constexpr const char kVmParams[] = "rdinit=/bin/init bin/vsock_client 2 45678 HelloWorld";
 static constexpr const char kTestMessage[] = "HelloWorld";
 
-TEST_F(VirtualizationTest, TestVsock) {
+bool isVmSupported() {
+    const std::array<const char *, 4> needed_files = {
+            "/dev/kvm",
+            "/dev/vhost-vsock",
+            "/apex/com.android.virt/bin/crosvm",
+            "/apex/com.android.virt/bin/virtualizationservice",
+    };
+    return std::all_of(needed_files.begin(), needed_files.end(),
+                       [](const char *file) { return access(file, F_OK) == 0; });
+}
+
+/** Returns true if the kernel supports Protected KVM. */
+bool isPkvmSupported() {
+    unique_fd kvm_fd(open("/dev/kvm", O_NONBLOCK | O_CLOEXEC));
+    return kvm_fd != 0 && ioctl(kvm_fd, KVM_CHECK_EXTENSION, KVM_CAP_ARM_PROTECTED_VM) == 1;
+}
+
+void runTest(sp<IVirtualizationService> virtualization_service, bool protected_vm) {
     binder::Status status;
 
     unique_fd server_fd(TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM, 0)));
@@ -64,9 +87,10 @@
     config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
     config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
     config.params = String16(kVmParams);
+    config.protected_vm = protected_vm;
 
     sp<IVirtualMachine> vm;
-    status = mVirtualizationService->startVm(config, std::nullopt, &vm);
+    status = virtualization_service->startVm(config, std::nullopt, &vm);
     ASSERT_TRUE(status.isOk()) << "Error starting VM: " << status;
 
     int32_t cid;
@@ -90,4 +114,22 @@
     ASSERT_EQ(msg, kTestMessage);
 }
 
+TEST_F(VirtualizationTest, TestVsock) {
+    if (!isVmSupported()) {
+        GTEST_SKIP() << "Device doesn't support KVM.";
+    }
+
+    runTest(mVirtualizationService, false);
+}
+
+TEST_F(VirtualizationTest, TestVsockProtected) {
+    if (!isVmSupported()) {
+        GTEST_SKIP() << "Device doesn't support KVM.";
+    } else if (!isPkvmSupported()) {
+        GTEST_SKIP() << "Skipping as pKVM is not supported on this device.";
+    }
+
+    runTest(mVirtualizationService, true);
+}
+
 } // namespace virt
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineConfig.aidl
index 6ca9cc7..cb28856 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineConfig.aidl
@@ -39,4 +39,7 @@
 
     /** Disk images to be made available to the VM. */
     DiskImage[] disks;
+
+    /** Whether the VM should be a protected VM. */
+    boolean protected_vm;
 }
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 0089bfc..b1b0b38 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -115,6 +115,7 @@
             initrd: as_asref(&config.initrd),
             disks,
             params: config.params.to_owned(),
+            protected: config.protected_vm,
         };
         let composite_disk_mappings: Vec<_> = indirect_files
             .iter()
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 797011c..669c631 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -39,6 +39,7 @@
     pub initrd: Option<&'a File>,
     pub disks: Vec<DiskFile>,
     pub params: Option<String>,
+    pub protected: bool,
 }
 
 /// A disk image to pass to crosvm for a VM.
@@ -55,6 +56,8 @@
     child: SharedChild,
     /// The CID assigned to the VM for vsock communication.
     pub cid: Cid,
+    /// Whether the VM is a protected VM.
+    pub protected: bool,
     /// Directory of temporary files used by the VM while it is running.
     pub temporary_directory: PathBuf,
     /// The UID of the process which requested the VM.
@@ -75,6 +78,7 @@
     fn new(
         child: SharedChild,
         cid: Cid,
+        protected: bool,
         temporary_directory: PathBuf,
         requester_uid: u32,
         requester_sid: String,
@@ -83,6 +87,7 @@
         VmInstance {
             child,
             cid,
+            protected,
             temporary_directory,
             requester_uid,
             requester_sid,
@@ -107,6 +112,7 @@
         let instance = Arc::new(VmInstance::new(
             child,
             config.cid,
+            config.protected,
             temporary_directory,
             requester_uid,
             requester_sid,
@@ -163,6 +169,10 @@
     // TODO(qwandor): Remove --disable-sandbox.
     command.arg("run").arg("--disable-sandbox").arg("--cid").arg(config.cid.to_string());
 
+    if config.protected {
+        command.arg("--protected-vm");
+    }
+
     if let Some(log_fd) = log_fd {
         command.stdout(log_fd);
     } else {
diff --git a/vm/src/config.rs b/vm/src/config.rs
index 169fdab..8ea0d8f 100644
--- a/vm/src/config.rs
+++ b/vm/src/config.rs
@@ -43,6 +43,9 @@
     /// Disk images to be made available to the VM.
     #[serde(default)]
     pub disks: Vec<DiskImage>,
+    /// Whether the VM should be a protected VM.
+    #[serde(default)]
+    pub protected: bool,
 }
 
 impl VmConfig {
@@ -80,6 +83,7 @@
             params: self.params.clone(),
             bootloader: maybe_open_parcel_file(&self.bootloader, false)?,
             disks: self.disks.iter().map(DiskImage::to_parcelable).collect::<Result<_, Error>>()?,
+            protected_vm: self.protected,
         })
     }
 }