Merge "Add a direct API for memory balloon control" into main
diff --git a/ferrochrome_app/custom_vm_setup.sh b/ferrochrome_app/custom_vm_setup.sh
index f007f6a..a5480ff 100644
--- a/ferrochrome_app/custom_vm_setup.sh
+++ b/ferrochrome_app/custom_vm_setup.sh
@@ -1,14 +1,31 @@
#!/system/bin/sh
-function copy_files() {
- cp -u /sdcard/vm_config.json /data/local/tmp
- cp -u /data/media/10/vm_config.json /data/local/tmp
- cp -u /sdcard/chromiumos_test_image.bin /data/local/tmp
- cp -u /data/media/10/chromiumos_test_image.bin /data/local/tmp
- chmod 666 /data/local/tmp/vm_config.json
- chmod 666 /data/local/tmp/chromiumos_test_image.bin
+function round_up() {
+ num=$1
+ div=$2
+ echo $((( (( ${num} / ${div} ) + 1) * ${div} )))
}
+
+function install() {
+ user=$(cmd user get-main-user)
+ src_dir=/data/media/${user}/ferrochrome/
+ dst_dir=/data/local/tmp/
+
+ cat $(find ${src_dir} -name "images.tar.gz*" | sort) | tar xz -C ${dst_dir}
+ cp -u ${src_dir}vm_config.json ${dst_dir}
+ chmod 666 ${dst_dir}*
+
+ # increase the size of state.img to the multiple of 4096
+ num_blocks=$(du -b -K ${dst_dir}state.img | cut -f 1)
+ required_num_blocks=$(round_up ${num_blocks} 4)
+ additional_blocks=$((( ${required_num_blocks} - ${num_blocks} )))
+ dd if=/dev/zero bs=512 count=${additional_blocks} >> ${dst_dir}state.img
+
+ rm ${src_dir}images.tar.gz*
+ rm ${src_dir}vm_config.json
+}
+
setprop debug.custom_vm_setup.done false
-copy_files
+install
setprop debug.custom_vm_setup.start false
setprop debug.custom_vm_setup.done true
diff --git a/ferrochrome_app/java/com/android/virtualization/ferrochrome/FerrochromeActivity.java b/ferrochrome_app/java/com/android/virtualization/ferrochrome/FerrochromeActivity.java
index 7c18537..58005aa 100644
--- a/ferrochrome_app/java/com/android/virtualization/ferrochrome/FerrochromeActivity.java
+++ b/ferrochrome_app/java/com/android/virtualization/ferrochrome/FerrochromeActivity.java
@@ -28,15 +28,11 @@
import android.view.WindowManager;
import android.widget.TextView;
-import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
-import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
-import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
-
-import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
+import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@@ -45,19 +41,17 @@
import java.util.concurrent.Executors;
public class FerrochromeActivity extends Activity {
- ExecutorService executorService = Executors.newSingleThreadExecutor();
- private static final String TAG = "FerrochromeActivity";
+ private static final String TAG = FerrochromeActivity.class.getName();
private static final String ACTION_VM_LAUNCHER = "android.virtualization.VM_LAUNCHER";
- private static final String FERROCHROME_VERSION = "R128-15926.0.0";
- private static final String EXTERNAL_STORAGE_DIR =
- Environment.getExternalStorageDirectory().getPath() + File.separator;
- private static final Path IMAGE_PATH =
- Path.of(EXTERNAL_STORAGE_DIR + "chromiumos_test_image.bin");
- private static final Path IMAGE_VERSION_INFO =
- Path.of(EXTERNAL_STORAGE_DIR + "ferrochrome_image_version");
- private static final Path VM_CONFIG_PATH = Path.of(EXTERNAL_STORAGE_DIR + "vm_config.json");
+
+ private static final Path DEST_DIR =
+ Path.of(Environment.getExternalStorageDirectory().getPath(), "ferrochrome");
+ private static final Path VERSION_FILE = Path.of(DEST_DIR.toString(), "version");
+
private static final int REQUEST_CODE_VMLAUNCHER = 1;
+ ExecutorService executorService = Executors.newSingleThreadExecutor();
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -80,35 +74,7 @@
executorService.execute(
() -> {
- if (Files.notExists(IMAGE_PATH)
- || !FERROCHROME_VERSION.equals(getVersionInfo())) {
- updateStatus("Starting first-time setup.");
- updateStatus(
- "Downloading Ferrochrome image. This can take about 5 to 10"
- + " minutes, depending on your network speed.");
- if (download(FERROCHROME_VERSION)) {
- updateStatus("Done.");
- } else {
- updateStatus(
- "Download failed. Check the internet connection and retry.");
- return;
- }
- } else {
- updateStatus("Ferrochrome is already downloaded.");
- }
- updateStatus("Updating VM config.");
- copyVmConfigJson();
- updateStatus("Updating VM images. This may take a few minutes.");
- SystemProperties.set("debug.custom_vm_setup.start", "true");
- while (!SystemProperties.getBoolean("debug.custom_vm_setup.done", false)) {
- // Wait for custom_vm_setup
- try {
- Thread.sleep(1000);
- } catch (Exception e) {
- Log.d(TAG, e.toString());
- }
- }
- updateStatus("Done.");
+ updateImageIfNeeded();
updateStatus("Starting Ferrochrome...");
runOnUiThread(() -> startActivityForResult(intent, REQUEST_CODE_VMLAUNCHER));
});
@@ -121,63 +87,86 @@
}
}
+ private void updateImageIfNeeded() {
+ if (!isUpdateNeeded()) {
+ Log.d(TAG, "No update needed.");
+ return;
+ }
+
+ updateStatus("Copying images...");
+ try {
+ if (Files.notExists(DEST_DIR)) {
+ Files.createDirectory(DEST_DIR);
+ }
+ for (String file : getAssets().list("ferrochrome")) {
+ updateStatus(file);
+ Path dst = Path.of(DEST_DIR.toString(), file);
+ updateFile(getAssets().open("ferrochrome/" + file), dst);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error while updating image: " + e);
+ updateStatus("Failed.");
+ return;
+ }
+ updateStatus("Done.");
+
+ updateStatus("Extracting images...");
+ SystemProperties.set("debug.custom_vm_setup.start", "true");
+ while (!SystemProperties.getBoolean("debug.custom_vm_setup.done", false)) {
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e) {
+ Log.e(TAG, "Error while extracting image: " + e);
+ updateStatus("Failed.");
+ return;
+ }
+ }
+ updateStatus("Done.");
+ }
+
+ private boolean isUpdateNeeded() {
+ Path[] pathsToCheck = {DEST_DIR, VERSION_FILE};
+ for (Path p : pathsToCheck) {
+ if (Files.notExists(p)) {
+ Log.d(TAG, p.toString() + " does not exist.");
+ return true;
+ }
+ }
+
+ try {
+ String installedVer = readLine(new FileInputStream(VERSION_FILE.toFile()));
+ String updatedVer = readLine(getAssets().open("ferrochrome/version"));
+ if (installedVer.equals(updatedVer)) {
+ return false;
+ }
+ Log.d(TAG, "Version mismatch. Installed: " + installedVer + " Updated: " + updatedVer);
+ } catch (IOException e) {
+ Log.e(TAG, "Error while checking version: " + e);
+ }
+ return true;
+ }
+
+ private static String readLine(InputStream input) throws IOException {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(input))) {
+ return reader.readLine();
+ } catch (IOException e) {
+ throw e;
+ }
+ }
+
+ private static void updateFile(InputStream input, Path path) throws IOException {
+ try {
+ Files.copy(input, path, StandardCopyOption.REPLACE_EXISTING);
+ } finally {
+ input.close();
+ }
+ }
+
private void updateStatus(String line) {
- Log.d(TAG, line);
runOnUiThread(
() -> {
TextView statusView = findViewById(R.id.status_txt_view);
statusView.append(line + "\n");
});
}
-
- private void copyVmConfigJson() {
- try (InputStream is = getResources().openRawResource(R.raw.vm_config)) {
- Files.copy(is, VM_CONFIG_PATH, StandardCopyOption.REPLACE_EXISTING);
- } catch (IOException e) {
- updateStatus(e.toString());
- }
- }
-
- private String getVersionInfo() {
- try {
- return new String(Files.readAllBytes(IMAGE_VERSION_INFO), StandardCharsets.UTF_8);
- } catch (IOException e) {
- return null;
- }
- }
-
- private boolean updateVersionInfo(String version) {
- try {
- Files.write(IMAGE_VERSION_INFO, version.getBytes(StandardCharsets.UTF_8));
- } catch (IOException e) {
- Log.d(TAG, e.toString());
- }
- return true;
- }
-
- private boolean download(String version) {
- String urlString =
- "https://storage.googleapis.com/chromiumos-image-archive/ferrochrome-public/"
- + version
- + "/chromiumos_test_image.tar.xz";
- try (InputStream is = (new URL(urlString)).openStream();
- XZCompressorInputStream xz = new XZCompressorInputStream(is);
- TarArchiveInputStream tar = new TarArchiveInputStream(xz)) {
- TarArchiveEntry entry;
- while ((entry = tar.getNextTarEntry()) != null) {
- if (!entry.getName().contains("chromiumos_test_image.bin")) {
- continue;
- }
- updateStatus("copy " + entry.getName() + " start");
- Files.copy(tar, IMAGE_PATH, StandardCopyOption.REPLACE_EXISTING);
- updateStatus("copy " + entry.getName() + " done");
- updateVersionInfo(version);
- break;
- }
- } catch (Exception e) {
- updateStatus(e.toString());
- return false;
- }
- return true;
- }
}
diff --git a/ferrochrome_app/repack.sh b/ferrochrome_app/repack.sh
new file mode 100755
index 0000000..d47b529
--- /dev/null
+++ b/ferrochrome_app/repack.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+# Repacks chromiumos_*.bin into the assets of FerrochromeApp
+
+usage() {
+ echo "Usage: $0 CHROME_OS_DISK_IMAGE"
+ exit 1
+}
+
+if [ "$#" -ne 1 ]; then
+ usage
+fi
+
+disk=$1
+
+loop=$(sudo losetup --show -f -P ${disk})
+kern=$(sudo fdisk -x ${loop} | grep KERN-A | awk "{print\$1}")
+root=$(sudo fdisk -x ${loop} | grep ROOT-A | awk "{print\$1}")
+efi=$(sudo fdisk -x ${loop} | grep EFI-SYSTEM | awk "{print\$1}")
+state=$(sudo fdisk -x ${loop} | grep STATE | awk "{print\$1}")
+root_guid=$(sudo fdisk -x ${loop} | grep ROOT-A | awk "{print\$6}")
+
+tempdir=$(mktemp -d)
+pushd ${tempdir} > /dev/null
+echo Extracting partition images...
+sudo cp --sparse=always ${kern} kernel.img
+sudo cp --sparse=always ${root} root.img
+sudo cp --sparse=always ${efi} efi.img
+sudo cp --sparse=always ${state} state.img
+sudo chmod 777 *.img
+
+echo Archiving. This can take long...
+tar czvS -f images.tar.gz *.img
+
+echo Calculating hash...
+hash=$(sha1sum images.tar.gz | cut -d' ' -f 1)
+
+echo Splitting...
+split -b 100M -d images.tar.gz images.tar.gz.part
+
+popd > /dev/null
+asset_dir=$(dirname $0)/assets/ferrochrome
+echo Updating ${asset_dir}...
+vm_config_template=$(dirname $0)/vm_config.json.template
+mkdir -p ${asset_dir}
+rm ${asset_dir}/images.tar.gz.part*
+mv ${tempdir}/images.tar.gz.part* ${asset_dir}
+sed -E s/GUID/${root_guid}/ ${vm_config_template} > ${asset_dir}/vm_config.json
+echo ${hash} > ${asset_dir}/version
+
+echo Cleanup...
+sudo losetup -d ${loop}
+rm -rf ${tempdir}
+echo Done.
diff --git a/ferrochrome_app/res/raw/vm_config.json b/ferrochrome_app/res/raw/vm_config.json
deleted file mode 100644
index d79400c..0000000
--- a/ferrochrome_app/res/raw/vm_config.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "cros",
- "disks": [
- {
- "image": "/data/local/tmp/chromiumos_test_image.bin",
- "partitions": [],
- "writable": true
- }
- ],
- "params": "root=/dev/vda3 rootwait noinitrd ro enforcing=0 cros_debug cros_secure",
- "protected": false,
- "cpu_topology": "match_host",
- "platform_version": "~1.0",
- "memory_mib": 8096,
- "gpu": {
- "backend": "virglrenderer",
- "context_types": ["virgl2"]
- },
- "console_input_device": "ttyS0"
-}
\ No newline at end of file
diff --git a/ferrochrome_app/vm_config.json.template b/ferrochrome_app/vm_config.json.template
new file mode 100644
index 0000000..cb968ec
--- /dev/null
+++ b/ferrochrome_app/vm_config.json.template
@@ -0,0 +1,37 @@
+{
+ "name": "cros",
+ "disks": [
+ {
+ "writable": true,
+ "partitions": [
+ {
+ "label": "STATE",
+ "path": "/data/local/tmp/state.img",
+ "writable": true
+ },
+ {
+ "label": "KERN-A",
+ "path": "/data/local/tmp/kernel.img"
+ },
+ {
+ "label": "ROOT-A",
+ "path": "/data/local/tmp/root.img",
+ "guid": "GUID"
+ },
+ {
+ "label": "EFI-SYSTEM",
+ "path": "/data/local/tmp/efi.img"
+ }
+ ]
+ }
+ ],
+ "protected": false,
+ "cpu_topology": "match_host",
+ "platform_version": "~1.0",
+ "memory_mib": 8096,
+ "gpu": {
+ "backend": "virglrenderer",
+ "context_types": ["virgl2"]
+ },
+ "console_input_device": "ttyS0"
+}
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachine.java b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
index 9b1fcd1..23269d9 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachine.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
@@ -912,11 +912,11 @@
if (vmConfig.getCustomImageConfig().useTouch()) {
ParcelFileDescriptor[] pfds = ParcelFileDescriptor.createSocketPair();
mTouchSock = pfds[0];
- InputDevice.SingleTouch t = new InputDevice.SingleTouch();
+ InputDevice.MultiTouch t = new InputDevice.MultiTouch();
t.width = rawConfig.displayConfig.width;
t.height = rawConfig.displayConfig.height;
t.pfd = pfds[1];
- inputDevices.add(InputDevice.singleTouch(t));
+ inputDevices.add(InputDevice.multiTouch(t));
}
if (vmConfig.getCustomImageConfig().useKeyboard()) {
ParcelFileDescriptor[] pfds = ParcelFileDescriptor.createSocketPair();
@@ -1070,7 +1070,7 @@
}
/** @hide */
- public boolean sendSingleTouchEvent(MotionEvent event) {
+ public boolean sendMultiTouchEvent(MotionEvent event) {
if (mTouchSock == null) {
Log.d(TAG, "mTouchSock == null");
return false;
@@ -1083,17 +1083,56 @@
short ABS_X = 0x00;
short ABS_Y = 0x01;
short SYN_REPORT = 0x00;
+ short ABS_MT_SLOT = 0x2f;
+ short ABS_MT_POSITION_X = 0x35;
+ short ABS_MT_POSITION_Y = 0x36;
+ short ABS_MT_TRACKING_ID = 0x39;
- int x = (int) event.getX();
- int y = (int) event.getY();
- boolean down = event.getAction() != MotionEvent.ACTION_UP;
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_MOVE:
+ List<InputEvent> events =
+ new ArrayList<>(
+ event.getPointerCount() * 6 /*InputEvent per a pointer*/
+ + 1 /*SYN*/);
+ for (int actionIdx = 0; actionIdx < event.getPointerCount(); actionIdx++) {
+ int pointerId = event.getPointerId(actionIdx);
+ int x = (int) event.getRawX(actionIdx);
+ int y = (int) event.getRawY(actionIdx);
+ events.add(new InputEvent(EV_ABS, ABS_MT_SLOT, pointerId));
+ events.add(new InputEvent(EV_ABS, ABS_MT_TRACKING_ID, pointerId));
+ events.add(new InputEvent(EV_ABS, ABS_MT_POSITION_X, x));
+ events.add(new InputEvent(EV_ABS, ABS_MT_POSITION_Y, y));
+ events.add(new InputEvent(EV_ABS, ABS_X, x));
+ events.add(new InputEvent(EV_ABS, ABS_Y, y));
+ }
+ events.add(new InputEvent(EV_SYN, SYN_REPORT, 0));
+ return writeEventsToSock(mTouchSock, events);
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ break;
+ default:
+ return false;
+ }
+ boolean down =
+ event.getActionMasked() == MotionEvent.ACTION_DOWN
+ || event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN;
+ int actionIdx = event.getActionIndex();
+ int pointerId = event.getPointerId(actionIdx);
+ int x = (int) event.getRawX(actionIdx);
+ int y = (int) event.getRawY(actionIdx);
return writeEventsToSock(
mTouchSock,
Arrays.asList(
+ new InputEvent(EV_KEY, BTN_TOUCH, down ? 1 : 0),
+ new InputEvent(EV_ABS, ABS_MT_SLOT, pointerId),
+ new InputEvent(EV_ABS, ABS_MT_TRACKING_ID, down ? pointerId : -1),
+ new InputEvent(EV_ABS, ABS_MT_POSITION_X, x),
+ new InputEvent(EV_ABS, ABS_MT_POSITION_Y, y),
new InputEvent(EV_ABS, ABS_X, x),
new InputEvent(EV_ABS, ABS_Y, y),
- new InputEvent(EV_KEY, BTN_TOUCH, down ? 1 : 0),
new InputEvent(EV_SYN, SYN_REPORT, 0)));
}
@@ -1128,6 +1167,9 @@
short EV_KEY = 0x01;
short BTN_TOUCH = 0x14a;
short BTN_TOOL_FINGER = 0x145;
+ short BTN_TOOL_DOUBLETAP = 0x14d;
+ short BTN_TOOL_TRIPLETAP = 0x14e;
+ short BTN_TOOL_QUADTAP = 0x14f;
short ABS_X = 0x00;
short ABS_Y = 0x01;
short SYN_REPORT = 0x00;
@@ -1149,29 +1191,114 @@
short ABS_PRESSURE = 0x18;
short ABS_TOOL_WIDTH = 0x1c;
- int x = (int) event.getRawX();
- int y = (int) event.getRawY();
- boolean down = event.getAction() != MotionEvent.ACTION_UP;
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_BUTTON_PRESS:
+ case MotionEvent.ACTION_BUTTON_RELEASE:
+ short BTN_LEFT = 0x110;
+ short keyCode;
+ switch (event.getActionButton()) {
+ case MotionEvent.BUTTON_PRIMARY:
+ keyCode = BTN_LEFT;
+ break;
+ default:
+ Log.d(TAG, event.toString());
+ return false;
+ }
+ return writeEventsToSock(
+ mMouseSock,
+ Arrays.asList(
+ new InputEvent(
+ EV_KEY,
+ keyCode,
+ event.getAction() == MotionEvent.ACTION_BUTTON_PRESS
+ ? 1
+ : 0),
+ new InputEvent(EV_SYN, SYN_REPORT, 0)));
+ case MotionEvent.ACTION_MOVE:
+ List<InputEvent> events =
+ new ArrayList<>(
+ event.getPointerCount() * 10 /*InputEvent per a pointer*/
+ + 1 /*SYN*/);
+ for (int actionIdx = 0; actionIdx < event.getPointerCount(); actionIdx++) {
+ int pointerId = event.getPointerId(actionIdx);
+ int x = (int) event.getRawX(actionIdx);
+ int y = (int) event.getRawY(actionIdx);
+ events.add(new InputEvent(EV_ABS, ABS_MT_SLOT, pointerId));
+ events.add(new InputEvent(EV_ABS, ABS_MT_TRACKING_ID, pointerId));
+ events.add(new InputEvent(EV_ABS, ABS_MT_POSITION_X, x));
+ events.add(new InputEvent(EV_ABS, ABS_MT_POSITION_Y, y));
+ events.add(
+ new InputEvent(
+ EV_ABS,
+ ABS_MT_TOUCH_MAJOR,
+ (short) event.getTouchMajor(actionIdx)));
+ events.add(
+ new InputEvent(
+ EV_ABS,
+ ABS_MT_TOUCH_MINOR,
+ (short) event.getTouchMinor(actionIdx)));
+ events.add(new InputEvent(EV_ABS, ABS_X, x));
+ events.add(new InputEvent(EV_ABS, ABS_Y, y));
+ events.add(
+ new InputEvent(
+ EV_ABS,
+ ABS_PRESSURE,
+ (short) (255 * event.getPressure(actionIdx))));
+ events.add(
+ new InputEvent(
+ EV_ABS,
+ ABS_MT_PRESSURE,
+ (short) (255 * event.getPressure(actionIdx))));
+ }
+ events.add(new InputEvent(EV_SYN, SYN_REPORT, 0));
+ return writeEventsToSock(mTrackpadSock, events);
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_POINTER_UP:
+ break;
+ default:
+ return false;
+ }
- // TODO(b/347253952): support multi-touch and button click
+ boolean down =
+ event.getActionMasked() == MotionEvent.ACTION_DOWN
+ || event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN;
+ int actionIdx = event.getActionIndex();
+ int pointerId = event.getPointerId(actionIdx);
+ int x = (int) event.getRawX(actionIdx);
+ int y = (int) event.getRawY(actionIdx);
return writeEventsToSock(
mTrackpadSock,
Arrays.asList(
new InputEvent(EV_KEY, BTN_TOUCH, down ? 1 : 0),
- new InputEvent(EV_KEY, BTN_TOOL_FINGER, down ? 1 : 0),
- new InputEvent(EV_ABS, ABS_MT_SLOT, 0),
new InputEvent(
- EV_ABS, ABS_MT_TRACKING_ID, down ? event.getPointerId(0) : -1),
+ EV_KEY,
+ BTN_TOOL_FINGER,
+ down && event.getPointerCount() == 1 ? 1 : 0),
+ new InputEvent(
+ EV_KEY, BTN_TOOL_DOUBLETAP, event.getPointerCount() == 2 ? 1 : 0),
+ new InputEvent(
+ EV_KEY, BTN_TOOL_TRIPLETAP, event.getPointerCount() == 3 ? 1 : 0),
+ new InputEvent(
+ EV_KEY, BTN_TOOL_QUADTAP, event.getPointerCount() > 4 ? 1 : 0),
+ new InputEvent(EV_ABS, ABS_MT_SLOT, pointerId),
+ new InputEvent(EV_ABS, ABS_MT_TRACKING_ID, down ? pointerId : -1),
new InputEvent(EV_ABS, ABS_MT_TOOL_TYPE, 0 /* MT_TOOL_FINGER */),
new InputEvent(EV_ABS, ABS_MT_POSITION_X, x),
new InputEvent(EV_ABS, ABS_MT_POSITION_Y, y),
- new InputEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, (short) event.getTouchMajor()),
- new InputEvent(EV_ABS, ABS_MT_TOUCH_MINOR, (short) event.getTouchMinor()),
+ new InputEvent(
+ EV_ABS, ABS_MT_TOUCH_MAJOR, (short) event.getTouchMajor(actionIdx)),
+ new InputEvent(
+ EV_ABS, ABS_MT_TOUCH_MINOR, (short) event.getTouchMinor(actionIdx)),
new InputEvent(EV_ABS, ABS_X, x),
new InputEvent(EV_ABS, ABS_Y, y),
- new InputEvent(EV_ABS, ABS_PRESSURE, (short) (255 * event.getPressure())),
new InputEvent(
- EV_ABS, ABS_MT_PRESSURE, (short) (255 * event.getPressure())),
+ EV_ABS, ABS_PRESSURE, (short) (255 * event.getPressure(actionIdx))),
+ new InputEvent(
+ EV_ABS,
+ ABS_MT_PRESSURE,
+ (short) (255 * event.getPressure(actionIdx))),
new InputEvent(EV_SYN, SYN_REPORT, 0)));
}
diff --git a/libs/hypervisor_props/src/lib.rs b/libs/hypervisor_props/src/lib.rs
index 6665bc5..14614fd 100644
--- a/libs/hypervisor_props/src/lib.rs
+++ b/libs/hypervisor_props/src/lib.rs
@@ -37,8 +37,3 @@
pub fn version() -> Result<Option<String>> {
Ok(hypervisorproperties::hypervisor_version()?)
}
-
-/// Returns if the hypervisor is pKVM
-pub fn is_pkvm() -> Result<bool> {
- Ok(version()?.unwrap_or_default().starts_with("kvm") && is_protected_vm_supported()?)
-}
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 2d83963..d62a4b4 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -813,6 +813,12 @@
width: u32::try_from(trackpad.width)?,
name: if !trackpad.name.is_empty() { Some(trackpad.name.clone()) } else { None },
},
+ InputDevice::MultiTouch(multi_touch) => InputDeviceOption::MultiTouch {
+ file: clone_file(multi_touch.pfd.as_ref().ok_or(anyhow!("pfd should have value"))?)?,
+ height: u32::try_from(multi_touch.height)?,
+ width: u32::try_from(multi_touch.width)?,
+ name: if !multi_touch.name.is_empty() { Some(multi_touch.name.clone()) } else { None },
+ },
})
}
/// Given the configuration for a disk image, assembles the `DiskFile` to pass to crosvm.
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index 4787abc..78dd9a2 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -222,6 +222,7 @@
Mouse(File),
Switches(File),
MultiTouchTrackpad { file: File, width: u32, height: u32, name: Option<String> },
+ MultiTouch { file: File, width: u32, height: u32, name: Option<String> },
}
type VfioDevice = Strong<dyn IBoundDevice>;
@@ -934,11 +935,8 @@
let swiotlb_size_mib = 2 * virtio_pci_device_count as u32;
command.arg("--swiotlb").arg(swiotlb_size_mib.to_string());
- // b/346770542 for consistent "usable" memory across protected and non-protected VMs under
- // pKVM.
- if hypervisor_props::is_pkvm()? {
- memory_mib = memory_mib.map(|m| m.saturating_add(swiotlb_size_mib));
- }
+ // b/346770542 for consistent "usable" memory across protected and non-protected VMs.
+ memory_mib = memory_mib.map(|m| m.saturating_add(swiotlb_size_mib));
// Workaround to keep crash_dump from trying to read protected guest memory.
// Context in b/238324526.
@@ -1156,6 +1154,13 @@
height,
name.as_ref().map_or("".into(), |n| format!(",name={}", n))
),
+ InputDeviceOption::MultiTouch { file, width, height, name } => format!(
+ "multi-touch[path={},width={},height={}{}]",
+ add_preserved_fd(&mut preserved_fds, file),
+ width,
+ height,
+ name.as_ref().map_or("".into(), |n| format!(",name={}", n))
+ ),
});
}
}
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl
index e998d02..bb06fff 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl
@@ -51,10 +51,20 @@
int height = 1080;
@utf8InCpp String name = "";
}
+
+ parcelable MultiTouch {
+ ParcelFileDescriptor pfd;
+ // Default values come from https://crosvm.dev/book/devices/input.html#multi-touch
+ int width = 1280;
+ int height = 1080;
+ @utf8InCpp String name = "";
+ }
+
SingleTouch singleTouch;
EvDev evDev;
Keyboard keyboard;
Mouse mouse;
Switches switches;
Trackpad trackpad;
+ MultiTouch multiTouch;
}
diff --git a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
index c2b1fa8..4980e55 100644
--- a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
+++ b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
@@ -352,7 +352,7 @@
if (mVirtualMachine == null) {
return false;
}
- return mVirtualMachine.sendSingleTouchEvent(event);
+ return mVirtualMachine.sendMultiTouchEvent(event);
});
surfaceView.requestUnbufferedDispatch(InputDevice.SOURCE_ANY);
surfaceView.setOnCapturedPointerListener(