未验证 提交 da5eb26b 编写于 作者: L LI DONGZE 提交者: GitHub

Reporting back native stacktrace to dart side for crash reporting. (#20280)

* Add native stacktrace on iOS

* Add native stacktrace on Android

* format and changing naming to errorWithCode on iOS

* reformat

* Remove stacktrace from decodeEnvelope, not needed.

* Separate encodeErrorEnvelopeWithStacktrace with original encode function

* Add unit tests

* re-format

* change comments for stacktrace

* Remove changes for iOS
Co-authored-by: NBen Li <libe@google.com>
上级 c78d57bd
......@@ -70,6 +70,17 @@ public final class JSONMethodCodec implements MethodCodec {
.put(JSONUtil.wrap(errorDetails)));
}
@Override
public ByteBuffer encodeErrorEnvelopeWithStacktrace(
String errorCode, String errorMessage, Object errorDetails, String errorStacktrace) {
return JSONMessageCodec.INSTANCE.encodeMessage(
new JSONArray()
.put(errorCode)
.put(JSONUtil.wrap(errorMessage))
.put(JSONUtil.wrap(errorDetails))
.put(JSONUtil.wrap(errorStacktrace)));
}
@Override
public Object decodeEnvelope(ByteBuffer envelope) {
try {
......
......@@ -11,6 +11,9 @@ import androidx.annotation.UiThread;
import io.flutter.BuildConfig;
import io.flutter.plugin.common.BinaryMessenger.BinaryMessageHandler;
import io.flutter.plugin.common.BinaryMessenger.BinaryReply;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.ByteBuffer;
/**
......@@ -247,8 +250,16 @@ public class MethodChannel {
});
} catch (RuntimeException e) {
Log.e(TAG + name, "Failed to handle method call", e);
reply.reply(codec.encodeErrorEnvelope("error", e.getMessage(), null));
reply.reply(
codec.encodeErrorEnvelopeWithStacktrace(
"error", e.getMessage(), null, getStackTrace(e)));
}
}
private String getStackTrace(Exception e) {
Writer result = new StringWriter();
e.printStackTrace(new PrintWriter(result));
return result.toString();
}
}
}
......@@ -55,6 +55,20 @@ public interface MethodCodec {
*/
ByteBuffer encodeErrorEnvelope(String errorCode, String errorMessage, Object errorDetails);
/**
* Encodes an error result into a binary envelope message with the native stacktrace.
*
* @param errorCode An error code String.
* @param errorMessage An error message String, possibly null.
* @param errorDetails Error details, possibly null. Consider supporting {@link Throwable} in your
* codec. This is the most common value passed to this field.
* @param errorStacktrace Platform stacktrace for the error. possibly null.
* @return a {@link ByteBuffer} containing the encoding between position 0 and the current
* position.
*/
ByteBuffer encodeErrorEnvelopeWithStacktrace(
String errorCode, String errorMessage, Object errorDetails, String errorStacktrace);
/**
* Decodes a result envelope from binary.
*
......
......@@ -79,6 +79,24 @@ public final class StandardMethodCodec implements MethodCodec {
return buffer;
}
@Override
public ByteBuffer encodeErrorEnvelopeWithStacktrace(
String errorCode, String errorMessage, Object errorDetails, String errorStacktrace) {
final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
stream.write(1);
messageCodec.writeValue(stream, errorCode);
messageCodec.writeValue(stream, errorMessage);
if (errorDetails instanceof Throwable) {
messageCodec.writeValue(stream, getStackTrace((Throwable) errorDetails));
} else {
messageCodec.writeValue(stream, errorDetails);
}
messageCodec.writeValue(stream, errorStacktrace);
final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
buffer.put(stream.buffer(), 0, stream.size());
return buffer;
}
@Override
public Object decodeEnvelope(ByteBuffer envelope) {
envelope.order(ByteOrder.nativeOrder());
......
......@@ -7,6 +7,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
......@@ -89,4 +90,27 @@ public class StandardMethodCodecTest {
"at io.flutter.plugin.common.StandardMethodCodecTest.encodeErrorEnvelopeWithThrowableTest(StandardMethodCodecTest.java:"));
}
}
@Test
public void encodeErrorEnvelopeWithStacktraceTest() {
final Exception e = new IllegalArgumentException("foo");
final ByteBuffer buffer =
StandardMethodCodec.INSTANCE.encodeErrorEnvelopeWithStacktrace(
"code", e.getMessage(), e, "error stacktrace");
assertNotNull(buffer);
buffer.flip();
buffer.order(ByteOrder.nativeOrder());
final byte flag = buffer.get();
final Object code = StandardMessageCodec.INSTANCE.readValue(buffer);
final Object message = StandardMessageCodec.INSTANCE.readValue(buffer);
final Object details = StandardMessageCodec.INSTANCE.readValue(buffer);
final Object stacktrace = StandardMessageCodec.INSTANCE.readValue(buffer);
assertEquals("code", (String) code);
assertEquals("foo", (String) message);
String stack = (String) details;
assertTrue(
stack.contains(
"at io.flutter.plugin.common.StandardMethodCodecTest.encodeErrorEnvelopeWithStacktraceTest(StandardMethodCodecTest.java:"));
assertEquals("error stacktrace", (String) stacktrace);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册