From e5b03a179a33c5806efd34d45dc01a0200194f80 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Wed, 18 May 2022 10:00:45 +0200 Subject: [PATCH] Emulator: handle OOM and Protocol error cases - OutOfMemoryError can happen naturally if the size of the clipboard is too large to allocate. We should prefer to drop the clipboard data if we have a choice between that and crashing the system server. - OutOfMemoryError can happen unnatturally if the protocol gets out of sync with the host. This can happen quite easily if there is a caught exception and the clipboard monitor tries to keep on trucking, since the protocol doesn't have any built in synchronisation to catch back up to the start of the next message again. The only option to prevent that at the moment is to just close the pipe and reopen it in case of failure to understand something. Bug: 231340598 Test: presubmit Change-Id: Icceb8ec8b3988c32a2eb5f5598a43753460fc26b --- .../clipboard/EmulatorClipboardMonitor.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java index ab3b2506f5ac8..dce1c9684987f 100644 --- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java +++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java @@ -29,6 +29,7 @@ import android.util.Slog; import java.io.EOFException; import java.io.FileDescriptor; import java.io.InterruptedIOException; +import java.net.ProtocolException; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -39,12 +40,16 @@ import java.util.function.Consumer; // write contents of the host system's clipboard. class EmulatorClipboardMonitor implements Consumer { private static final String TAG = "EmulatorClipboardMonitor"; + 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 static final int MAX_CLIPBOARD_BYTES = 128 << 20; + private FileDescriptor mPipe = null; + private final Thread mHostMonitorThread; private static byte[] createOpenHandshake() { // String.getBytes doesn't include the null terminator, @@ -97,8 +102,8 @@ class EmulatorClipboardMonitor implements Consumer { return fd; } - private static byte[] receiveMessage(final FileDescriptor fd) throws ErrnoException, - InterruptedIOException, EOFException { + private byte[] receiveMessage(final FileDescriptor fd) throws ErrnoException, + InterruptedIOException, EOFException, ProtocolException { final byte[] lengthBits = new byte[4]; readFully(fd, lengthBits, 0, lengthBits.length); @@ -106,6 +111,10 @@ class EmulatorClipboardMonitor implements Consumer { bb.order(ByteOrder.LITTLE_ENDIAN); final int msgLen = bb.getInt(); + if (msgLen <= 0 || msgLen > MAX_CLIPBOARD_BYTES) { + throw new ProtocolException("Clipboard message length: " + msgLen + " out of bounds."); + } + final byte[] msg = new byte[msgLen]; readFully(fd, msg, 0, msg.length); @@ -150,7 +159,8 @@ class EmulatorClipboardMonitor implements Consumer { } setAndroidClipboard.accept(clip); } catch (ErrnoException | EOFException | InterruptedIOException - | InterruptedException e) { + | InterruptedException | ProtocolException | OutOfMemoryError e) { + Slog.w(TAG, "Failure to read from host clipboard", e); setPipeFD(null); try {