Merge "Edit the description for the vm launcher app" into main
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachine.java b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
index 51b91ca..1076219 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachine.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
@@ -63,6 +63,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.system.virtualizationcommon.DeathReason;
import android.system.virtualizationcommon.ErrorCode;
@@ -102,6 +103,7 @@
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -161,6 +163,7 @@
public static final long MAX_VSOCK_PORT = (1L << 32) - 1;
private ParcelFileDescriptor mTouchSock;
+ private ParcelFileDescriptor mKeySock;
/**
* Status of a virtual machine
@@ -861,25 +864,48 @@
// Handle input devices here
List<InputDevice> inputDevices = new ArrayList<>();
if (vmConfig.getCustomImageConfig() != null
- && vmConfig.getCustomImageConfig().useTouch()
&& rawConfig.displayConfig != null) {
- ParcelFileDescriptor[] pfds = ParcelFileDescriptor.createSocketPair();
- mTouchSock = pfds[0];
- InputDevice.SingleTouch t = new InputDevice.SingleTouch();
- t.width = rawConfig.displayConfig.width;
- t.height = rawConfig.displayConfig.height;
- t.pfd = pfds[1];
- inputDevices.add(InputDevice.singleTouch(t));
+ if (vmConfig.getCustomImageConfig().useTouch()) {
+ ParcelFileDescriptor[] pfds = ParcelFileDescriptor.createSocketPair();
+ mTouchSock = pfds[0];
+ InputDevice.SingleTouch t = new InputDevice.SingleTouch();
+ t.width = rawConfig.displayConfig.width;
+ t.height = rawConfig.displayConfig.height;
+ t.pfd = pfds[1];
+ inputDevices.add(InputDevice.singleTouch(t));
+ }
+ if (vmConfig.getCustomImageConfig().useKeyboard()) {
+ ParcelFileDescriptor[] pfds = ParcelFileDescriptor.createSocketPair();
+ mKeySock = pfds[0];
+ InputDevice.Keyboard k = new InputDevice.Keyboard();
+ k.pfd = pfds[1];
+ inputDevices.add(InputDevice.keyboard(k));
+ }
}
rawConfig.inputDevices = inputDevices.toArray(new InputDevice[0]);
return android.system.virtualizationservice.VirtualMachineConfig.rawConfig(rawConfig);
}
- private void addInputEvent(ByteBuffer buffer, short type, short code, int value) {
- buffer.putShort(type);
- buffer.putShort(code);
- buffer.putInt(value);
+ private static record InputEvent(short type, short code, int value) {}
+
+ /** @hide */
+ public boolean sendKeyEvent(KeyEvent event) {
+ if (mKeySock == null) {
+ Log.d(TAG, "mKeySock == null");
+ return false;
+ }
+ // from include/uapi/linux/input-event-codes.h in the kernel.
+ short EV_SYN = 0x00;
+ short EV_KEY = 0x01;
+ short SYN_REPORT = 0x00;
+ boolean down = event.getAction() != MotionEvent.ACTION_UP;
+
+ return writeEventsToSock(
+ mKeySock,
+ Arrays.asList(
+ new InputEvent(EV_KEY, (short) event.getScanCode(), down ? 1 : 0),
+ new InputEvent(EV_SYN, SYN_REPORT, 0)));
}
/** @hide */
@@ -901,24 +927,30 @@
int y = (int) event.getY();
boolean down = event.getAction() != MotionEvent.ACTION_UP;
+ return writeEventsToSock(
+ mTouchSock,
+ Arrays.asList(
+ 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)));
+ }
+
+ private boolean writeEventsToSock(ParcelFileDescriptor sock, List<InputEvent> evtList) {
ByteBuffer byteBuffer =
- ByteBuffer.allocate(32 /* (type: u16 + code: u16 + value: i32) * 4 */);
+ ByteBuffer.allocate(8 /* (type: u16 + code: u16 + value: i32) */ * evtList.size());
byteBuffer.clear();
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
-
- addInputEvent(byteBuffer, EV_ABS, ABS_X, x);
- addInputEvent(byteBuffer, EV_ABS, ABS_Y, y);
- addInputEvent(byteBuffer, EV_KEY, BTN_TOUCH, down ? 1 : 0);
- addInputEvent(byteBuffer, EV_SYN, SYN_REPORT, 0);
-
+ for (InputEvent e : evtList) {
+ byteBuffer.putShort(e.type);
+ byteBuffer.putShort(e.code);
+ byteBuffer.putInt(e.value);
+ }
try {
IoBridge.write(
- mTouchSock.getFileDescriptor(),
- byteBuffer.array(),
- 0,
- byteBuffer.array().length);
+ sock.getFileDescriptor(), byteBuffer.array(), 0, byteBuffer.array().length);
} catch (IOException e) {
- Log.d(TAG, "cannot send touch evt", e);
+ Log.d(TAG, "cannot send event", e);
return false;
}
return true;
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java b/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
index 7cf5893..8d294fd 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachineCustomImageConfig.java
@@ -35,6 +35,7 @@
private static final String KEY_DISK_IMAGES = "disk_images";
private static final String KEY_DISPLAY_CONFIG = "display_config";
private static final String KEY_TOUCH = "touch";
+ private static final String KEY_KEYBOARD = "keyboard";
@Nullable private final String name;
@NonNull private final String kernelPath;
@@ -44,6 +45,7 @@
@Nullable private final Disk[] disks;
@Nullable private final DisplayConfig displayConfig;
private final boolean touch;
+ private final boolean keyboard;
@Nullable
public Disk[] getDisks() {
@@ -79,6 +81,10 @@
return touch;
}
+ public boolean useKeyboard() {
+ return keyboard;
+ }
+
/** @hide */
public VirtualMachineCustomImageConfig(
String name,
@@ -88,7 +94,8 @@
String[] params,
Disk[] disks,
DisplayConfig displayConfig,
- boolean touch) {
+ boolean touch,
+ boolean keyboard) {
this.name = name;
this.kernelPath = kernelPath;
this.initrdPath = initrdPath;
@@ -97,6 +104,7 @@
this.disks = disks;
this.displayConfig = displayConfig;
this.touch = touch;
+ this.keyboard = keyboard;
}
static VirtualMachineCustomImageConfig from(PersistableBundle customImageConfigBundle) {
@@ -125,6 +133,7 @@
customImageConfigBundle.getPersistableBundle(KEY_DISPLAY_CONFIG);
builder.setDisplayConfig(DisplayConfig.from(displayConfigPb));
builder.useTouch(customImageConfigBundle.getBoolean(KEY_TOUCH));
+ builder.useKeyboard(customImageConfigBundle.getBoolean(KEY_KEYBOARD));
return builder.build();
}
@@ -154,6 +163,7 @@
.map(dc -> dc.toPersistableBundle())
.orElse(null));
pb.putBoolean(KEY_TOUCH, touch);
+ pb.putBoolean(KEY_KEYBOARD, keyboard);
return pb;
}
@@ -203,6 +213,7 @@
private List<Disk> disks = new ArrayList<>();
private DisplayConfig displayConfig;
private boolean touch;
+ private boolean keyboard;
/** @hide */
public Builder() {}
@@ -256,6 +267,12 @@
}
/** @hide */
+ public Builder useKeyboard(boolean keyboard) {
+ this.keyboard = keyboard;
+ return this;
+ }
+
+ /** @hide */
public VirtualMachineCustomImageConfig build() {
return new VirtualMachineCustomImageConfig(
this.name,
@@ -265,7 +282,8 @@
this.params.toArray(new String[0]),
this.disks.toArray(new Disk[0]),
displayConfig,
- touch);
+ touch,
+ keyboard);
}
}
diff --git a/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java b/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
index 678e56f..f456cb4 100644
--- a/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
+++ b/service_vm/test_apk/src/java/com/android/virt/rkpd/vm_attestation/testapp/RkpdVmAttestationTest.java
@@ -95,6 +95,11 @@
if (mGki == null) {
// We don't need this permission to use the microdroid kernel.
revokePermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
+ } else {
+ // The permission is needed to use the GKI kernel.
+ // Granting the permission is needed as the microdroid kernel test setup
+ // can revoke the permission before the GKI kernel test.
+ grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
}
prepareTestSetup(true /* protectedVm */, mGki);
setMaxPerformanceTaskProfile();
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index c5f1ab7..99a0078 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -751,6 +751,9 @@
InputDevice::EvDev(evdev) => InputDeviceOption::EvDev(clone_file(
evdev.pfd.as_ref().ok_or(anyhow!("pfd should have value"))?,
)?),
+ InputDevice::Keyboard(keyboard) => InputDeviceOption::Keyboard(clone_file(
+ keyboard.pfd.as_ref().ok_or(anyhow!("pfd should have value"))?,
+ )?),
})
}
/// 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 4be48a5..040e552 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -161,6 +161,7 @@
pub enum InputDeviceOption {
EvDev(File),
SingleTouch { file: File, width: u32, height: u32, name: Option<String> },
+ Keyboard(File),
}
type VfioDevice = Strong<dyn IBoundDevice>;
@@ -976,12 +977,24 @@
}
if cfg!(paravirtualized_devices) {
+ // TODO(b/325929096): Need to set up network from the config
+ if rustutils::system_properties::read_bool("ro.crosvm.network.setup.done", false)
+ .unwrap_or(false)
+ {
+ command.arg("--net").arg("tap-name=crosvm_tap");
+ }
+ }
+
+ if cfg!(paravirtualized_devices) {
for input_device_option in config.input_device_options.iter() {
command.arg("--input");
command.arg(match input_device_option {
InputDeviceOption::EvDev(file) => {
format!("evdev[path={}]", add_preserved_fd(&mut preserved_fds, file))
}
+ InputDeviceOption::Keyboard(file) => {
+ format!("keyboard[path={}]", add_preserved_fd(&mut preserved_fds, file))
+ }
InputDeviceOption::SingleTouch { file, width, height, name } => format!(
"single-touch[path={},width={},height={}{}]",
add_preserved_fd(&mut preserved_fds, file),
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl
index fe12291..712d6a9 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/InputDevice.aidl
@@ -30,7 +30,11 @@
parcelable EvDev {
ParcelFileDescriptor pfd;
}
-
+ // Keyboard input
+ parcelable Keyboard {
+ ParcelFileDescriptor pfd;
+ }
SingleTouch singleTouch;
EvDev evDev;
+ Keyboard keyboard;
}
diff --git a/vmlauncher_app/AndroidManifest.xml b/vmlauncher_app/AndroidManifest.xml
index 607a895..d800ec7 100644
--- a/vmlauncher_app/AndroidManifest.xml
+++ b/vmlauncher_app/AndroidManifest.xml
@@ -4,9 +4,11 @@
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
+ <uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.software.virtualization_framework" android:required="true" />
<application
- android:label="VmLauncherApp">
+ android:label="VmLauncherApp"
+ android:networkSecurityConfig="@xml/network_security_config">
<activity android:name=".MainActivity"
android:enabled="false"
android:screenOrientation="landscape"
diff --git a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
index 450f4ed..4c42bb4 100644
--- a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
+++ b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
@@ -37,6 +37,7 @@
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
@@ -127,6 +128,7 @@
customImageConfigBuilder.setDisplayConfig(displayConfigBuilder.build());
customImageConfigBuilder.useTouch(true);
+ customImageConfigBuilder.useKeyboard(true);
configBuilder.setCustomImageConfig(customImageConfigBuilder.build());
@@ -137,6 +139,22 @@
}
@Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (mVirtualMachine == null) {
+ return false;
+ }
+ return mVirtualMachine.sendKeyEvent(event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (mVirtualMachine == null) {
+ return false;
+ }
+ return mVirtualMachine.sendKeyEvent(event);
+ }
+
+ @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
diff --git a/vmlauncher_app/res/xml/network_security_config.xml b/vmlauncher_app/res/xml/network_security_config.xml
new file mode 100644
index 0000000..f27fa56
--- /dev/null
+++ b/vmlauncher_app/res/xml/network_security_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">localhost</domain>
+ </domain-config>
+</network-security-config>