diff --git a/android/src/main/java/com/facebook/flipper/plugins/common/MainThreadFlipperReceiver.java b/android/src/main/java/com/facebook/flipper/plugins/common/MainThreadFlipperReceiver.java index 31adb5e25..91ad6c19f 100644 --- a/android/src/main/java/com/facebook/flipper/plugins/common/MainThreadFlipperReceiver.java +++ b/android/src/main/java/com/facebook/flipper/plugins/common/MainThreadFlipperReceiver.java @@ -9,32 +9,47 @@ package com.facebook.flipper.plugins.common; import android.os.Handler; import android.os.Looper; -import com.facebook.flipper.core.ErrorReportingRunnable; import com.facebook.flipper.core.FlipperConnection; import com.facebook.flipper.core.FlipperObject; import com.facebook.flipper.core.FlipperReceiver; import com.facebook.flipper.core.FlipperResponder; +import java.io.PrintWriter; +import java.io.StringWriter; public abstract class MainThreadFlipperReceiver implements FlipperReceiver { public MainThreadFlipperReceiver(FlipperConnection connection) { - this.mConnection = connection; + // TODO(T41065412): remove unused constructor argument. } - private final FlipperConnection mConnection; private final Handler mHandler = new Handler(Looper.getMainLooper()); @Override public final void onReceive(final FlipperObject params, final FlipperResponder responder) { mHandler.post( - new ErrorReportingRunnable(mConnection) { + new Runnable() { @Override - public void runOrThrow() throws Exception { - onReceiveOnMainThread(params, responder); + public void run() { + try { + onReceiveOnMainThread(params, responder); + } catch (Exception ex) { + responder.error( + new FlipperObject.Builder() + .put("name", ex.getClass().getCanonicalName()) + .put("message", ex.getMessage()) + .put("stacktrace", getStackTraceString(ex)) + .build()); + } } }); } + private static String getStackTraceString(Throwable th) { + StringWriter stringWriter = new StringWriter(); + th.printStackTrace(new PrintWriter(stringWriter)); + return stringWriter.toString(); + } + public abstract void onReceiveOnMainThread(FlipperObject params, FlipperResponder responder) throws Exception; } diff --git a/android/src/test/java/com/facebook/flipper/plugins/common/MainThreadFlipperReceiverTest.java b/android/src/test/java/com/facebook/flipper/plugins/common/MainThreadFlipperReceiverTest.java new file mode 100644 index 000000000..a9aab982a --- /dev/null +++ b/android/src/test/java/com/facebook/flipper/plugins/common/MainThreadFlipperReceiverTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the LICENSE + * file in the root directory of this source tree. + * + */ +package com.facebook.flipper.plugins.common; + +import com.facebook.flipper.core.FlipperObject; +import com.facebook.flipper.core.FlipperResponder; +import com.facebook.flipper.testing.FlipperConnectionMock; +import com.facebook.flipper.testing.FlipperResponderMock; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class MainThreadFlipperReceiverTest { + + FlipperConnectionMock connection; + FlipperResponderMock responder; + + @Before + public void setup() throws Exception { + connection = new FlipperConnectionMock(); + responder = new FlipperResponderMock(); + } + + @Test + public void errorIsPassedToResponder() throws Exception { + MainThreadFlipperReceiver receiver = + new MainThreadFlipperReceiver(connection) { + public void onReceiveOnMainThread(FlipperObject params, FlipperResponder responder) + throws Exception { + throw new RuntimeException("hello exception"); + } + }; + + receiver.onReceive(new FlipperObject.Builder().build(), responder); + + Assert.assertEquals(1, responder.errors.size()); + FlipperObject error = responder.errors.get(0); + Assert.assertEquals("hello exception", error.getString("message")); + Assert.assertEquals("java.lang.RuntimeException", error.getString("name")); + Assert.assertTrue( + error.getString("stacktrace").contains(MainThreadFlipperReceiver.class.getCanonicalName())); + } +}