diff options
author | Luis Hector Chavez <lhchavez@google.com> | 2018-06-14 11:26:30 -0700 |
---|---|---|
committer | Luis Hector Chavez <lhchavez@google.com> | 2018-07-13 13:13:43 -0700 |
commit | 1fef1a678393e55d295f295a1d0e5fff89a5c725 (patch) | |
tree | 5d9a5d290782d5d70ca74b885f6e910a245e175b | |
parent | 1ec13ff8a419faa4bfa859400c6eee6d50ce2a7e (diff) | |
download | libchrome-1fef1a678393e55d295f295a1d0e5fff89a5c725.tar.gz |
[mojo]: Add a way to handle unhandled RuntimeExceptionsandroid-n-iot-release-smart-display-r2
This change makes it possible to allow interfaces to globally handle
unhandled RuntimeExceptions, in their bindings or in the callbacks.
Bug: 28814913
Test: Android-on-Chrome OS has the same behavior as before
Test: Android-on-Chrome OS, when setting the DefaultExceptionHandler's
delegate can now forward the unhandled exceptions to the crash
server.
Change-Id: I2b7455a0344a109e1d2416a74ad4a0b98cd007f0
Reviewed-on: https://chromium-review.googlesource.com/1101898
Reviewed-by: Ken Rockot <rockot@chromium.org>
Commit-Queue: Luis Hector Chavez <lhchavez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568128}
4 files changed, 201 insertions, 3 deletions
diff --git a/libchrome_tools/patch/mojo-Add-a-way-to-handle-unhandled-RuntimeExceptions.patch b/libchrome_tools/patch/mojo-Add-a-way-to-handle-unhandled-RuntimeExceptions.patch new file mode 100644 index 0000000000..f5ac205ce3 --- /dev/null +++ b/libchrome_tools/patch/mojo-Add-a-way-to-handle-unhandled-RuntimeExceptions.patch @@ -0,0 +1,129 @@ +From 4256ecec730fdf5a41f34e11c0641e072971cb8c Mon Sep 17 00:00:00 2001 +From: Luis Hector Chavez <lhchavez@google.com> +Date: Mon, 18 Jun 2018 20:14:56 +0000 +Subject: [PATCH] [mojo] Add a way to handle unhandled RuntimeExceptions + +This change makes it possible to allow interfaces to globally handle +unhandled RuntimeExceptions, in their bindings or in the callbacks. + + delegate can now forward the unhandled exceptions to the crash + server. + +Bug: 810087 +Test: Android-on-Chrome OS has the same behavior as before +Test: Android-on-Chrome OS, when setting the DefaultExceptionHandler's +Change-Id: I2b7455a0344a109e1d2416a74ad4a0b98cd007f0 +Reviewed-on: https://chromium-review.googlesource.com/1101898 +Reviewed-by: Ken Rockot <rockot@chromium.org> +Commit-Queue: Luis Hector Chavez <lhchavez@chromium.org> +Cr-Commit-Position: refs/heads/master@{#568128} +--- + mojo/public/java/BUILD.gn | 1 + + .../org/chromium/mojo/bindings/Connector.java | 12 +++- + .../mojo/bindings/ExceptionHandler.java | 59 +++++++++++++++++++ + 3 files changed, 70 insertions(+), 2 deletions(-) + create mode 100644 mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java + +diff --git a/mojo/public/java/BUILD.gn b/mojo/public/java/BUILD.gn +index 14951f4f0959..259e09cf7c07 100644 +--- a/mojo/public/java/BUILD.gn ++++ b/mojo/public/java/BUILD.gn +@@ -41,6 +41,7 @@ android_library("bindings_java") { + "bindings/src/org/chromium/mojo/bindings/DelegatingConnectionErrorHandler.java", + "bindings/src/org/chromium/mojo/bindings/DeserializationException.java", + "bindings/src/org/chromium/mojo/bindings/Encoder.java", ++ "bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java", + "bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java", + "bindings/src/org/chromium/mojo/bindings/HandleOwner.java", + "bindings/src/org/chromium/mojo/bindings/InterfaceControlMessagesHelper.java", +diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java +index 3a6d67112ce0..45f1fc7462e8 100644 +--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java ++++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java +@@ -201,8 +201,16 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle + ReadMessageResult readResult = result.getValue(); + assert readResult != null; + if (receiver != null) { +- boolean accepted = receiver.accept( +- new Message(ByteBuffer.wrap(readResult.mData), readResult.mHandles)); ++ boolean accepted; ++ try { ++ accepted = receiver.accept( ++ new Message(ByteBuffer.wrap(readResult.mData), readResult.mHandles)); ++ } catch (RuntimeException e) { ++ // The DefaultExceptionHandler will decide whether any uncaught exception will ++ // close the connection or not. ++ accepted = ++ ExceptionHandler.DefaultExceptionHandler.getInstance().handleException(e); ++ } + return new ResultAnd<Boolean>(result.getMojoResult(), accepted); + } + return new ResultAnd<Boolean>(result.getMojoResult(), false); +diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java +new file mode 100644 +index 000000000000..8961d22d3ee4 +--- /dev/null ++++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java +@@ -0,0 +1,59 @@ ++// Copyright 2018 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++package org.chromium.mojo.bindings; ++ ++/** ++ * An {@link ExceptionHandler} is notified of any {@link RuntimeException} happening in the ++ * bindings or any of the callbacks. ++ */ ++public interface ExceptionHandler { ++ /** ++ * Receives a notification that an unhandled {@link RuntimeException} has been thrown in an ++ * {@link Interface} implementation or one of the {@link Callbacks} internal classes. ++ * ++ * Normal implementations should either throw the exception or return whether the connection ++ * should be kept alive or terminated. ++ */ ++ public boolean handleException(RuntimeException e); ++ ++ /** ++ * The default ExceptionHandler, which simply throws the exception upon receiving it. It can ++ * also delegate the handling of the exceptions to another instance of ExceptionHandler. ++ */ ++ public static class DefaultExceptionHandler implements ExceptionHandler { ++ private ExceptionHandler mDelegate; ++ ++ @Override ++ public boolean handleException(RuntimeException e) { ++ if (mDelegate != null) { ++ return mDelegate.handleException(e); ++ } ++ throw e; ++ } ++ ++ private DefaultExceptionHandler() {} ++ ++ /** ++ * Static class that implements the initialization-on-demand holder idiom. ++ */ ++ private static class LazyHolder { ++ static final DefaultExceptionHandler INSTANCE = new DefaultExceptionHandler(); ++ } ++ ++ /** ++ * Gets the singleton instance for the DefaultExceptionHandler. ++ */ ++ public static DefaultExceptionHandler getInstance() { ++ return LazyHolder.INSTANCE; ++ } ++ ++ /** ++ * Sets a delegate ExceptionHandler, in case throwing an exception is not desirable. ++ */ ++ public void setDelegate(ExceptionHandler exceptionHandler) { ++ mDelegate = exceptionHandler; ++ } ++ } ++} +-- +2.18.0.203.gfac676dfb9-goog + diff --git a/mojo/public/java/BUILD.gn b/mojo/public/java/BUILD.gn index 078064114e..850785aa2c 100644 --- a/mojo/public/java/BUILD.gn +++ b/mojo/public/java/BUILD.gn @@ -37,6 +37,7 @@ android_library("bindings_java") { "bindings/src/org/chromium/mojo/bindings/DelegatingConnectionErrorHandler.java", "bindings/src/org/chromium/mojo/bindings/DeserializationException.java", "bindings/src/org/chromium/mojo/bindings/Encoder.java", + "bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java", "bindings/src/org/chromium/mojo/bindings/ExecutorFactory.java", "bindings/src/org/chromium/mojo/bindings/HandleOwner.java", "bindings/src/org/chromium/mojo/bindings/InterfaceControlMessagesHelper.java", diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java index 2aa5ea690c..d58602ab29 100644 --- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java +++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Connector.java @@ -169,7 +169,9 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle ResultAnd<Boolean> result; do { try { - result = readAndDispatchMessage(mMessagePipeHandle, mIncomingMessageReceiver); + result = readAndDispatchMessage( + mMessagePipeHandle, mIncomingMessageReceiver, + ExceptionHandler.DefaultExceptionHandler.getInstance()); } catch (MojoException e) { onError(e); return; @@ -191,9 +193,11 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle * * @param receiver The {@link MessageReceiver} that will receive the read {@link Message}. Can * be <code>null</code>, in which case the message is discarded. + * @param exceptionHandler The {@link ExceptionHandler} that can decide whether any uncaught + * exception will close the connection or not. */ static ResultAnd<Boolean> readAndDispatchMessage( - MessagePipeHandle handle, MessageReceiver receiver) { + MessagePipeHandle handle, MessageReceiver receiver, ExceptionHandler exceptionHandler) { // TODO(qsr) Allow usage of a pool of pre-allocated buffer for performance. ResultAnd<ReadMessageResult> result = handle.readMessage(null, 0, MessagePipeHandle.ReadFlags.NONE); @@ -206,7 +210,12 @@ public class Connector implements MessageReceiver, HandleOwner<MessagePipeHandle result = handle.readMessage( buffer, readResult.getHandlesCount(), MessagePipeHandle.ReadFlags.NONE); if (receiver != null && result.getMojoResult() == MojoResult.OK) { - boolean accepted = receiver.accept(new Message(buffer, result.getValue().getHandles())); + boolean accepted; + try { + accepted = receiver.accept(new Message(buffer, result.getValue().getHandles())); + } catch (RuntimeException e) { + accepted = exceptionHandler.handleException(e); + } return new ResultAnd<Boolean>(result.getMojoResult(), accepted); } return new ResultAnd<Boolean>(result.getMojoResult(), false); diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java new file mode 100644 index 0000000000..8961d22d3e --- /dev/null +++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/ExceptionHandler.java @@ -0,0 +1,59 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.bindings; + +/** + * An {@link ExceptionHandler} is notified of any {@link RuntimeException} happening in the + * bindings or any of the callbacks. + */ +public interface ExceptionHandler { + /** + * Receives a notification that an unhandled {@link RuntimeException} has been thrown in an + * {@link Interface} implementation or one of the {@link Callbacks} internal classes. + * + * Normal implementations should either throw the exception or return whether the connection + * should be kept alive or terminated. + */ + public boolean handleException(RuntimeException e); + + /** + * The default ExceptionHandler, which simply throws the exception upon receiving it. It can + * also delegate the handling of the exceptions to another instance of ExceptionHandler. + */ + public static class DefaultExceptionHandler implements ExceptionHandler { + private ExceptionHandler mDelegate; + + @Override + public boolean handleException(RuntimeException e) { + if (mDelegate != null) { + return mDelegate.handleException(e); + } + throw e; + } + + private DefaultExceptionHandler() {} + + /** + * Static class that implements the initialization-on-demand holder idiom. + */ + private static class LazyHolder { + static final DefaultExceptionHandler INSTANCE = new DefaultExceptionHandler(); + } + + /** + * Gets the singleton instance for the DefaultExceptionHandler. + */ + public static DefaultExceptionHandler getInstance() { + return LazyHolder.INSTANCE; + } + + /** + * Sets a delegate ExceptionHandler, in case throwing an exception is not desirable. + */ + public void setDelegate(ExceptionHandler exceptionHandler) { + mDelegate = exceptionHandler; + } + } +} |