vmterminal: Run crosvm(virtiofs) from app domain
Bug: 378451265
Test: Launch terminal app - verify virtiofs mount points
Run basic I/O test on virtiofs mounts
Change-Id: Ic9e0d7f11b0795adacb8526414bb6d8e1fad0804
Signed-off-by: Akilesh Kailash <akailash@google.com>
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
index ab03049..bd1af49 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/ConfigJson.java
@@ -16,6 +16,7 @@
package com.android.virtualization.terminal;
+
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Rect;
@@ -39,6 +40,7 @@
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
@@ -209,13 +211,26 @@
GUEST_GID,
0007,
"android",
- "android");
+ "android",
+ false, /* app domain is set to false so that crosvm is spin up as child of virtmgr */
+ "");
}
return null;
}
+ Path socketPath = context.getFilesDir().toPath().resolve("internal.virtiofs");
+ Files.deleteIfExists(socketPath);
return new SharedPath(
- sharedPath, terminalUid, terminalUid, 0, 0, 0007, "internal", "internal");
- } catch (NameNotFoundException e) {
+ sharedPath,
+ terminalUid,
+ terminalUid,
+ 0,
+ 0,
+ 0007,
+ "internal",
+ "internal",
+ true, /* app domain is set to true so that crosvm is spin up from app context */
+ socketPath.toString());
+ } catch (NameNotFoundException | IOException e) {
return null;
}
}
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 55de0af..c2f7663 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -1018,7 +1018,12 @@
guest_gid: path.guestGid,
mask: path.mask,
tag: path.tag.clone(),
- socket_path: temporary_directory.join(&path.socket).to_string_lossy().to_string(),
+ socket_path: temporary_directory
+ .join(&path.socketPath)
+ .to_string_lossy()
+ .to_string(),
+ socket_fd: maybe_clone_file(&path.socketFd)?,
+ app_domain: path.appDomain,
})
})
.collect()
diff --git a/android/virtmgr/src/crosvm.rs b/android/virtmgr/src/crosvm.rs
index 1ccabec..a385b82 100644
--- a/android/virtmgr/src/crosvm.rs
+++ b/android/virtmgr/src/crosvm.rs
@@ -235,6 +235,8 @@
pub mask: i32,
pub tag: String,
pub socket_path: String,
+ pub socket_fd: Option<File>,
+ pub app_domain: bool,
}
/// virtio-input device configuration from `external/crosvm/src/crosvm/config.rs`
@@ -912,6 +914,9 @@
fn run_virtiofs(config: &CrosvmConfig) -> io::Result<()> {
for shared_path in &config.shared_paths {
+ if shared_path.app_domain {
+ continue;
+ }
let ugid_map_value = format!(
"{} {} {} {} {} /",
shared_path.guest_uid,
@@ -1267,12 +1272,23 @@
}
for shared_path in &config.shared_paths {
- if let Err(e) = wait_for_file(&shared_path.socket_path, 5) {
- bail!("Error waiting for file: {}", e);
+ if shared_path.app_domain {
+ if let Some(socket_fd) = &shared_path.socket_fd {
+ let socket_path =
+ add_preserved_fd(&mut preserved_fds, socket_fd.try_clone().unwrap());
+ let raw_fd: i32 = socket_path.rsplit_once('/').unwrap().1.parse().unwrap();
+ command
+ .arg("--vhost-user-fs")
+ .arg(format!("tag={},socket-fd={}", &shared_path.tag, raw_fd));
+ }
+ } else {
+ if let Err(e) = wait_for_file(&shared_path.socket_path, 5) {
+ bail!("Error waiting for file: {}", e);
+ }
+ command
+ .arg("--vhost-user-fs")
+ .arg(format!("{},tag={}", &shared_path.socket_path, &shared_path.tag));
}
- command
- .arg("--vhost-user-fs")
- .arg(format!("{},tag={}", &shared_path.socket_path, &shared_path.tag));
}
debug!("Preserving FDs {:?}", preserved_fds);
diff --git a/android/virtualizationservice/aidl/android/system/virtualizationservice/SharedPath.aidl b/android/virtualizationservice/aidl/android/system/virtualizationservice/SharedPath.aidl
index 7be7a5f..71ec02c 100644
--- a/android/virtualizationservice/aidl/android/system/virtualizationservice/SharedPath.aidl
+++ b/android/virtualizationservice/aidl/android/system/virtualizationservice/SharedPath.aidl
@@ -39,5 +39,11 @@
String tag;
/** socket name for vhost-user-fs */
- String socket;
+ String socketPath;
+
+ /** socket fd for crosvm to connect */
+ @nullable ParcelFileDescriptor socketFd;
+
+ /** crosvm started from appDomain */
+ boolean appDomain;
}
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index 8230166..3829f9f 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -33,6 +33,8 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
@@ -56,6 +58,8 @@
import java.io.OutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -635,6 +639,34 @@
}
}
+ private void startCrosvmVirtiofs(
+ String sharedPath,
+ int host_uid,
+ int guest_uid,
+ int guest_gid,
+ String tagName,
+ int mask,
+ String socketPath)
+ throws IOException {
+ String ugidMapValue =
+ String.format("%d %d %d %d %d /", guest_uid, guest_gid, host_uid, host_uid, mask);
+ String cfgArg = String.format("ugid_map='%s'", ugidMapValue);
+ ProcessBuilder pb =
+ new ProcessBuilder(
+ "/apex/com.android.virt/bin/crosvm",
+ "device",
+ "fs",
+ "--socket=" + socketPath,
+ "--tag=" + tagName,
+ "--shared-dir=" + sharedPath,
+ "--cfg",
+ cfgArg,
+ "--disable-sandbox",
+ "--skip-pivot-root=true");
+
+ pb.start();
+ }
+
VirtualMachineRawConfig toVsRawConfig() throws IllegalStateException, IOException {
VirtualMachineRawConfig config = new VirtualMachineRawConfig();
VirtualMachineCustomImageConfig customImageConfig = getCustomImageConfig();
@@ -714,6 +746,38 @@
.orElse(0)];
for (int i = 0; i < config.sharedPaths.length; i++) {
config.sharedPaths[i] = customImageConfig.getSharedPaths()[i].toParcelable();
+ if (config.sharedPaths[i].appDomain) {
+ try {
+ String socketPath = customImageConfig.getSharedPaths()[i].getSocketPath();
+ startCrosvmVirtiofs(
+ config.sharedPaths[i].sharedPath,
+ config.sharedPaths[i].hostUid,
+ config.sharedPaths[i].guestUid,
+ config.sharedPaths[i].guestGid,
+ config.sharedPaths[i].tag,
+ config.sharedPaths[i].mask,
+ socketPath);
+ long startTime = System.currentTimeMillis();
+ long deadline = startTime + 5000;
+ // TODO: use socketpair instead of crosvm creating the named sockets.
+ while (!Files.exists(Path.of(socketPath))
+ && System.currentTimeMillis() < deadline) {
+ Thread.sleep(200);
+ }
+ if (!Files.exists(Path.of(socketPath))) {
+ throw new IOException("Timeout waiting for socket: " + socketPath);
+ }
+ LocalSocket socket = new LocalSocket();
+ socket.connect(
+ new LocalSocketAddress(
+ socketPath, LocalSocketAddress.Namespace.FILESYSTEM));
+ config.sharedPaths[i].socketFd =
+ ParcelFileDescriptor.dup(socket.getFileDescriptor());
+ } catch (IOException | InterruptedException e) {
+ Log.e(TAG, "startCrosvmVirtiofs failed", e);
+ throw new RuntimeException(e);
+ }
+ }
}
config.displayConfig =
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
index 9b0709d..93f29a9 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
@@ -317,6 +317,8 @@
private final int mask;
private final String tag;
private final String socket;
+ private final boolean appDomain;
+ private final String socketPath;
public SharedPath(
String path,
@@ -326,7 +328,9 @@
int guestGid,
int mask,
String tag,
- String socket) {
+ String socket,
+ boolean appDomain,
+ String socketPath) {
this.path = path;
this.hostUid = hostUid;
this.hostGid = hostGid;
@@ -335,6 +339,8 @@
this.mask = mask;
this.tag = tag;
this.socket = socket;
+ this.appDomain = appDomain;
+ this.socketPath = socketPath;
}
android.system.virtualizationservice.SharedPath toParcelable() {
@@ -347,7 +353,8 @@
parcelable.guestGid = this.guestGid;
parcelable.mask = this.mask;
parcelable.tag = this.tag;
- parcelable.socket = this.socket;
+ parcelable.socketPath = this.socket;
+ parcelable.appDomain = this.appDomain;
return parcelable;
}
@@ -390,6 +397,16 @@
public String getSocket() {
return socket;
}
+
+ /** @hide */
+ public boolean getAppDomain() {
+ return appDomain;
+ }
+
+ /** @hide */
+ public String getSocketPath() {
+ return socketPath;
+ }
}
/** @hide */