Implement plain text clipboard sharing from Android to VM
Bug: 349702327
Test: Run Ferrochrome, copy text in Android, and paste text in
Ferrochrome
Change-Id: Ie4b687c80d90efa4dbc1c653e68c21daf0101308
diff --git a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
index e9262ed..a3ecae7 100644
--- a/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
+++ b/vmlauncher_app/java/com/android/virtualization/vmlauncher/MainActivity.java
@@ -17,10 +17,13 @@
package com.android.virtualization.vmlauncher;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.ParcelFileDescriptor.AutoCloseOutputStream;
import static android.system.virtualmachine.VirtualMachineConfig.CPU_TOPOLOGY_MATCH_HOST;
import android.Manifest.permission;
import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.crosvm.ICrosvmAndroidDisplayService;
import android.graphics.PixelFormat;
import android.graphics.Rect;
@@ -79,6 +82,7 @@
private ExecutorService mExecutorService;
private VirtualMachine mVirtualMachine;
private ParcelFileDescriptor mCursorStream;
+ private ClipboardManager mClipboardManager;
private static final int RECORD_AUDIO_PERMISSION_REQUEST_CODE = 101;
private VirtualMachineConfig createVirtualMachineConfig(String jsonPath) {
@@ -459,6 +463,76 @@
Log.d(TAG, "destroyed");
}
+ private static final int CLIPBOARD_SHARING_SERVER_PORT = 3580;
+ // TODO(349702313): Introduce READ_CLIPBOARD_FROM_VM as 0 for reading clipboard from
+ // VM.
+ // TODO(349702313): Introduce WRITE_CLIPBOARD_TYPE_EMPTY as 1 for receiving empty clipboard data
+ // from VM.
+ private static final byte WRITE_CLIPBOARD_TYPE_TEXT_PLAIN = 2;
+
+ private ClipboardManager getClipboardManager() {
+ if (mClipboardManager == null) {
+ mClipboardManager = getSystemService(ClipboardManager.class);
+ }
+ return mClipboardManager;
+ }
+
+ // Construct header for the clipboard data.
+ // Byte 0: Data type
+ // Byte 1-3: Padding alignment & Reserved for other use cases in the future
+ // Byte 4-7: Data size of the payload
+ private ByteBuffer constructClipboardHeader(byte type, int dataSize) {
+ ByteBuffer header = ByteBuffer.allocate(8);
+ header.clear();
+ header.order(ByteOrder.LITTLE_ENDIAN);
+ header.put(0, type);
+ header.putInt(4, dataSize);
+ return header;
+ }
+
+ private ParcelFileDescriptor connectClipboardSharingServer() {
+ ParcelFileDescriptor pfd;
+ try {
+ // TODO(349702313): Consider when clipboard sharing server is started to run in VM.
+ pfd = mVirtualMachine.connectVsock(CLIPBOARD_SHARING_SERVER_PORT);
+ } catch (VirtualMachineException e) {
+ Log.d(TAG, "cannot connect to the clipboard sharing server", e);
+ return null;
+ }
+ return pfd;
+ }
+
+ private boolean writeClipboardToVm() {
+ ClipboardManager clipboardManager = getClipboardManager();
+
+ if (!clipboardManager.hasPrimaryClip()) {
+ Log.d(TAG, "host device has no clipboard data");
+ return true;
+ }
+ ClipData clip = clipboardManager.getPrimaryClip();
+ String text = clip.getItemAt(0).getText().toString();
+ ByteBuffer header =
+ constructClipboardHeader(
+ WRITE_CLIPBOARD_TYPE_TEXT_PLAIN, text.getBytes().length + 1);
+
+ ParcelFileDescriptor pfd = connectClipboardSharingServer();
+ if (pfd == null) {
+ Log.d(TAG, "file descriptor of ClipboardSharingServer is null");
+ return false;
+ }
+ OutputStream stream = new AutoCloseOutputStream(pfd);
+ try {
+ stream.write(header.array());
+ stream.write(text.getBytes());
+ stream.flush();
+ Log.d(TAG, "successfully wrote clipboard data to the VM");
+ return true;
+ } catch (IOException e) {
+ Log.e(TAG, "failed to write clipboard data to the VM", e);
+ return false;
+ }
+ }
+
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@@ -467,6 +541,12 @@
Log.d(TAG, "requestPointerCapture()");
surfaceView.requestPointerCapture();
}
+ if (mVirtualMachine != null) {
+ if (hasFocus) {
+ Log.d(TAG, "writing clipboard of host device into VM");
+ writeClipboardToVm();
+ }
+ }
}
@FunctionalInterface