From 935e7d4ca23f1e39b0928388038888167c70354f Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 3 Mar 2022 12:59:45 -0800 Subject: Log emulator's clipboard access to logcat to help debugging clipboard issues. Bug: 219611030 Bug: 206758809 Bug: 232284244 Test: boot the emulator with Test: `-append-userspace-opt androidboot.qemu.log_clipboard_access=1` Test: use the clipboard, check the logcat for Test: messages from EmulatorClipboardMonitor Signed-off-by: Roman Kiryanov Change-Id: I7fc0a96560f4e9805fd3bc91cb5b40a1fc149141 Merged-In: I7fc0a96560f4e9805fd3bc91cb5b40a1fc149141 --- .../com/android/server/clipboard/EmulatorClipboardMonitor.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java index 62b701aff398..11c451e01d4c 100644 --- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java +++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java @@ -18,6 +18,7 @@ package com.android.server.clipboard; import android.annotation.Nullable; import android.content.ClipData; +import android.os.SystemProperties; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -39,6 +40,8 @@ class EmulatorClipboardMonitor implements Consumer { private static final String PIPE_NAME = "pipe:clipboard"; private static final int HOST_PORT = 5000; private final Thread mHostMonitorThread; + private static final boolean LOG_CLIBOARD_ACCESS = + SystemProperties.getBoolean("ro.boot.qemu.log_clipboard_access", false); private FileDescriptor mPipe = null; private static byte[] createOpenHandshake() { @@ -132,6 +135,9 @@ class EmulatorClipboardMonitor implements Consumer { new String[]{"text/plain"}, new ClipData.Item(str)); + if (LOG_CLIBOARD_ACCESS) { + Slog.i(TAG, "Setting the guest clipboard to '" + str + "'"); + } setAndroidClipboard.accept(clip); } catch (ErrnoException | InterruptedIOException e) { closePipe(); @@ -156,6 +162,10 @@ class EmulatorClipboardMonitor implements Consumer { } private void setHostClipboardImpl(final String value) { + if (LOG_CLIBOARD_ACCESS) { + Slog.i(TAG, "Setting the host clipboard to '" + value + "'"); + } + try { if (isPipeOpened()) { sendMessage(value.getBytes()); -- cgit v1.2.3-59-g8ed1b From 0a11904976a913cdef2c1669fb3b95b7bdaa16cf Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Thu, 3 Mar 2022 21:33:44 -0800 Subject: Set host's clipboard in a separate thread It is not recommended to do IO in the UI thread. Bug: 219611030 Bug: 232284244 Test: boot AOSP, check if clipboard works Signed-off-by: Roman Kiryanov Change-Id: Iaf445ae3e6e009b86ccf4d1783dffeebc165bb62 Merged-In: Iaf445ae3e6e009b86ccf4d1783dffeebc165bb62 --- .../server/clipboard/EmulatorClipboardMonitor.java | 37 +++++++++++++--------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java index 11c451e01d4c..28c7cad3b184 100644 --- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java +++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java @@ -54,8 +54,8 @@ class EmulatorClipboardMonitor implements Consumer { return bits; } - private boolean isPipeOpened() { - return mPipe != null; + private synchronized FileDescriptor getPipeFD() { + return mPipe; } private synchronized boolean openPipe() { @@ -107,14 +107,16 @@ class EmulatorClipboardMonitor implements Consumer { return msg; } - private void sendMessage(final byte[] msg) throws ErrnoException, InterruptedIOException { + private static void sendMessage( + final FileDescriptor fd, + final byte[] msg) throws ErrnoException, InterruptedIOException { final byte[] lengthBits = new byte[4]; final ByteBuffer bb = ByteBuffer.wrap(lengthBits); bb.order(ByteOrder.LITTLE_ENDIAN); bb.putInt(msg.length); - Os.write(mPipe, lengthBits, 0, lengthBits.length); - Os.write(mPipe, msg, 0, msg.length); + Os.write(fd, lengthBits, 0, lengthBits.length); + Os.write(fd, msg, 0, msg.length); } EmulatorClipboardMonitor(final Consumer setAndroidClipboard) { @@ -162,17 +164,22 @@ class EmulatorClipboardMonitor implements Consumer { } private void setHostClipboardImpl(final String value) { - if (LOG_CLIBOARD_ACCESS) { - Slog.i(TAG, "Setting the host clipboard to '" + value + "'"); - } + final FileDescriptor pipeFD = getPipeFD(); - try { - if (isPipeOpened()) { - sendMessage(value.getBytes()); - } - } catch (ErrnoException | InterruptedIOException e) { - Slog.e(TAG, "Failed to set host clipboard " + e.getMessage()); - } catch (IllegalArgumentException e) { + if (pipeFD != null) { + Thread t = new Thread(() -> { + if (LOG_CLIBOARD_ACCESS) { + Slog.i(TAG, "Setting the host clipboard to '" + value + "'"); + } + + try { + sendMessage(pipeFD, value.getBytes()); + } catch (ErrnoException | InterruptedIOException e) { + Slog.e(TAG, "Failed to set host clipboard " + e.getMessage()); + } catch (IllegalArgumentException e) { + } + }); + t.start(); } } } -- cgit v1.2.3-59-g8ed1b From 63b433025938094c4d453fffc8964e96ef0dee99 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Mon, 9 May 2022 19:35:11 -0700 Subject: Add wrappers around IO functions to check the return values Os.read and Os.write don't throw exceptions if `fd` is closed on the other end. Bug: 231345789 Bug: 232284244 Test: save a snapshot Test: use clipboard both, check if there is no Test: infinite loops which sets the clipboard Signed-off-by: Roman Kiryanov Change-Id: If98fb3adf58f2e4e13d483b78ea05ea9d8d61b58 Merged-In: If98fb3adf58f2e4e13d483b78ea05ea9d8d61b58 --- .../server/clipboard/EmulatorClipboardMonitor.java | 41 ++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java index 28c7cad3b184..0944c57d121f 100644 --- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java +++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java @@ -25,6 +25,7 @@ import android.system.OsConstants; import android.system.VmSocketAddress; import android.util.Slog; +import java.io.EOFException; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.net.SocketException; @@ -93,16 +94,16 @@ class EmulatorClipboardMonitor implements Consumer { } } - private byte[] receiveMessage() throws ErrnoException, InterruptedIOException { + private byte[] receiveMessage() throws ErrnoException, InterruptedIOException, EOFException { final byte[] lengthBits = new byte[4]; - Os.read(mPipe, lengthBits, 0, lengthBits.length); + readFully(mPipe, lengthBits, 0, lengthBits.length); final ByteBuffer bb = ByteBuffer.wrap(lengthBits); bb.order(ByteOrder.LITTLE_ENDIAN); final int msgLen = bb.getInt(); final byte[] msg = new byte[msgLen]; - Os.read(mPipe, msg, 0, msg.length); + readFully(mPipe, msg, 0, msg.length); return msg; } @@ -115,8 +116,8 @@ class EmulatorClipboardMonitor implements Consumer { bb.order(ByteOrder.LITTLE_ENDIAN); bb.putInt(msg.length); - Os.write(fd, lengthBits, 0, lengthBits.length); - Os.write(fd, msg, 0, msg.length); + writeFully(fd, lengthBits, 0, lengthBits.length); + writeFully(fd, msg, 0, msg.length); } EmulatorClipboardMonitor(final Consumer setAndroidClipboard) { @@ -141,7 +142,7 @@ class EmulatorClipboardMonitor implements Consumer { Slog.i(TAG, "Setting the guest clipboard to '" + str + "'"); } setAndroidClipboard.accept(clip); - } catch (ErrnoException | InterruptedIOException e) { + } catch (ErrnoException | EOFException | InterruptedIOException e) { closePipe(); } catch (InterruptedException | IllegalArgumentException e) { } @@ -182,4 +183,32 @@ class EmulatorClipboardMonitor implements Consumer { t.start(); } } + + private static void readFully(final FileDescriptor fd, + final byte[] buf, int offset, int size) + throws ErrnoException, InterruptedIOException, EOFException { + while (size > 0) { + final int r = Os.read(fd, buf, offset, size); + if (r > 0) { + offset += r; + size -= r; + } else { + throw new EOFException(); + } + } + } + + private static void writeFully(final FileDescriptor fd, + final byte[] buf, int offset, int size) + throws ErrnoException, InterruptedIOException { + while (size > 0) { + final int r = Os.write(fd, buf, offset, size); + if (r > 0) { + offset += r; + size -= r; + } else { + throw new ErrnoException("write", OsConstants.EIO); + } + } + } } -- cgit v1.2.3-59-g8ed1b From 3c23790a7db7186f77336eed815d1398a7124645 Mon Sep 17 00:00:00 2001 From: Roman Kiryanov Date: Wed, 11 May 2022 21:55:05 -0700 Subject: Cleanup in EmulatorClipboardMonitor (1) Bug: 231345789 Test: presubmit Signed-off-by: Roman Kiryanov Change-Id: I3e96ab6ada8f0c892613a1f9dcc6b6ae12f6d73b Merged-In: I3e96ab6ada8f0c892613a1f9dcc6b6ae12f6d73b --- .../java/com/android/server/clipboard/EmulatorClipboardMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java index 0944c57d121f..14259df9879c 100644 --- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java +++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java @@ -71,7 +71,7 @@ class EmulatorClipboardMonitor implements Consumer { Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST)); final byte[] handshake = createOpenHandshake(); - Os.write(fd, handshake, 0, handshake.length); + writeFully(fd, handshake, 0, handshake.length); mPipe = fd; return true; } catch (ErrnoException | SocketException | InterruptedIOException e) { -- cgit v1.2.3-59-g8ed1b