diff --git a/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java b/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java index d80148958..0f87cabda 100644 --- a/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java +++ b/test-app/app/src/main/java/com/tns/NativeScriptUncaughtExceptionHandler.java @@ -31,7 +31,7 @@ public void uncaughtException(Thread thread, Throwable ex) { Runtime runtime = Runtime.getCurrentRuntime(); if (runtime != null) { - runtime.passUncaughtExceptionToJs(ex, ex.getMessage(), stackTraceErrorMessage); + runtime.passUncaughtExceptionToJs(ex, ex.getMessage(), Runtime.getJSStackTrace(ex), stackTraceErrorMessage); } } catch (Throwable t) { if (Util.isDebuggableApp(context)) { diff --git a/test-app/runtime/src/main/cpp/Runtime.cpp b/test-app/runtime/src/main/cpp/Runtime.cpp index 1fc8d74a1..7eaec8ab4 100644 --- a/test-app/runtime/src/main/cpp/Runtime.cpp +++ b/test-app/runtime/src/main/cpp/Runtime.cpp @@ -368,7 +368,7 @@ bool Runtime::TryCallGC() { return success; } -void Runtime::PassExceptionToJsNative(JNIEnv* env, jobject obj, jthrowable exception, jstring message, jstring stackTrace, jboolean isDiscarded) { +void Runtime::PassExceptionToJsNative(JNIEnv* env, jobject obj, jthrowable exception, jstring message, jstring fullStackTrace, jstring jsStackTrace, jboolean isDiscarded) { auto isolate = m_isolate; string errMsg = ArgConverter::jstringToString(message); @@ -391,7 +391,10 @@ void Runtime::PassExceptionToJsNative(JNIEnv* env, jobject obj, jthrowable excep //create a JS error object auto context = isolate->GetCurrentContext(); errObj->Set(context, V8StringConstants::GetNativeException(isolate), nativeExceptionObject); - errObj->Set(context, V8StringConstants::GetStackTrace(isolate), ArgConverter::jstringToV8String(isolate, stackTrace)); + errObj->Set(context, V8StringConstants::GetStackTrace(isolate), ArgConverter::jstringToV8String(isolate, fullStackTrace)); + if (jsStackTrace != NULL) { + errObj->Set(context, V8StringConstants::GetStack(isolate), ArgConverter::jstringToV8String(isolate, jsStackTrace)); + } //pass err to JS NativeScriptException::CallJsFuncWithErr(errObj, isDiscarded); diff --git a/test-app/runtime/src/main/cpp/Runtime.h b/test-app/runtime/src/main/cpp/Runtime.h index ec5a0ebd2..d4aa7d32a 100644 --- a/test-app/runtime/src/main/cpp/Runtime.h +++ b/test-app/runtime/src/main/cpp/Runtime.h @@ -52,7 +52,7 @@ class Runtime { void AdjustAmountOfExternalAllocatedMemory(); bool NotifyGC(JNIEnv* env, jobject obj); bool TryCallGC(); - void PassExceptionToJsNative(JNIEnv* env, jobject obj, jthrowable exception, jstring message, jstring stackTrace, jboolean isDiscarded); + void PassExceptionToJsNative(JNIEnv* env, jobject obj, jthrowable exception, jstring message, jstring fullStackTrace, jstring jsStackTrace, jboolean isDiscarded); void PassUncaughtExceptionFromWorkerToMainHandler(v8::Local message, v8::Local stackTrace, v8::Local filename, int lineno); void ClearStartupData(JNIEnv* env, jobject obj); void DestroyRuntime(); diff --git a/test-app/runtime/src/main/cpp/V8StringConstants.cpp b/test-app/runtime/src/main/cpp/V8StringConstants.cpp index 4dc909f2d..d018cd168 100644 --- a/test-app/runtime/src/main/cpp/V8StringConstants.cpp +++ b/test-app/runtime/src/main/cpp/V8StringConstants.cpp @@ -51,6 +51,12 @@ Local V8StringConstants::GetNativeException(Isolate* isolate) { return Local::New(isolate, *consts->NATIVE_EXCEPTION_PERSISTENT); } +Local V8StringConstants::GetStack(Isolate* isolate) { + auto consts = GetConstantsForIsolate(isolate); + + return Local::New(isolate, *consts->STACK_PERSISTENT); +} + Local V8StringConstants::GetStackTrace(Isolate* isolate) { auto consts = GetConstantsForIsolate(isolate); @@ -130,6 +136,7 @@ const string V8StringConstants::NULL_NODE_NAME = "nullNode"; const string V8StringConstants::IS_PROTOTYPE_IMPLEMENTATION_OBJECT = "__isPrototypeImplementationObject"; const string V8StringConstants::NATIVE_EXCEPTION = "nativeException"; const string V8StringConstants::STACK_TRACE = "stackTrace"; +const string V8StringConstants::STACK = "stack"; const string V8StringConstants::LONG_NUMBER = "NativeScriptLongNumber"; const string V8StringConstants::PROTOTYPE = "prototype"; const string V8StringConstants::SUPER = "super"; diff --git a/test-app/runtime/src/main/cpp/V8StringConstants.h b/test-app/runtime/src/main/cpp/V8StringConstants.h index d812372b4..eb707ea51 100644 --- a/test-app/runtime/src/main/cpp/V8StringConstants.h +++ b/test-app/runtime/src/main/cpp/V8StringConstants.h @@ -21,6 +21,8 @@ class V8StringConstants { static v8::Local GetNativeException(v8::Isolate* isolate); + static v8::Local GetStack(v8::Isolate* isolate); + static v8::Local GetStackTrace(v8::Isolate* isolate); static v8::Local GetLongNumber(v8::Isolate* isolate); @@ -52,6 +54,7 @@ class V8StringConstants { static const std::string NULL_NODE_NAME; static const std::string IS_PROTOTYPE_IMPLEMENTATION_OBJECT; static const std::string NATIVE_EXCEPTION; + static const std::string STACK; static const std::string STACK_TRACE; static const std::string LONG_NUMBER; static const std::string PROTOTYPE; @@ -96,6 +99,8 @@ class V8StringConstants { str = String::NewFromUtf8(isolate, NATIVE_EXCEPTION.c_str()).ToLocalChecked(); NATIVE_EXCEPTION_PERSISTENT = new Persistent(isolate, str); + str = String::NewFromUtf8(isolate, STACK.c_str()).ToLocalChecked(); + STACK_PERSISTENT = new Persistent(isolate, str); str = String::NewFromUtf8(isolate, STACK_TRACE.c_str()).ToLocalChecked(); STACK_TRACE_PERSISTENT = new Persistent(isolate, str); @@ -151,6 +156,7 @@ class V8StringConstants { NULL_NODE_NAME_PERSISTENT->Reset(); IS_PROTOTYPE_IMPLEMENTATION_OBJECT_PERSISTENT->Reset(); NATIVE_EXCEPTION_PERSISTENT->Reset(); + STACK_PERSISTENT->Reset(); STACK_TRACE_PERSISTENT->Reset(); LONG_NUMBER_PERSISTENT->Reset(); PROTOTYPE_PERSISTENT->Reset(); @@ -171,6 +177,7 @@ class V8StringConstants { v8::Persistent* NULL_NODE_NAME_PERSISTENT; v8::Persistent* IS_PROTOTYPE_IMPLEMENTATION_OBJECT_PERSISTENT; v8::Persistent* NATIVE_EXCEPTION_PERSISTENT; + v8::Persistent* STACK_PERSISTENT; v8::Persistent* STACK_TRACE_PERSISTENT; v8::Persistent* LONG_NUMBER_PERSISTENT; v8::Persistent* PROTOTYPE_PERSISTENT; diff --git a/test-app/runtime/src/main/cpp/com_tns_Runtime.cpp b/test-app/runtime/src/main/cpp/com_tns_Runtime.cpp index dfce4193d..11eed26c0 100644 --- a/test-app/runtime/src/main/cpp/com_tns_Runtime.cpp +++ b/test-app/runtime/src/main/cpp/com_tns_Runtime.cpp @@ -245,7 +245,7 @@ extern "C" JNIEXPORT void Java_com_tns_Runtime_unlock(JNIEnv* env, jobject obj, } } -extern "C" JNIEXPORT void Java_com_tns_Runtime_passExceptionToJsNative(JNIEnv* env, jobject obj, jint runtimeId, jthrowable exception, jstring message, jstring stackTrace, jboolean isDiscarded) { +extern "C" JNIEXPORT void Java_com_tns_Runtime_passExceptionToJsNative(JNIEnv* env, jobject obj, jint runtimeId, jthrowable exception, jstring message, jstring fullStackTrace, jstring jsStackTrace, jboolean isDiscarded) { auto runtime = TryGetRuntime(runtimeId); if (runtime == nullptr) { return; @@ -256,7 +256,7 @@ extern "C" JNIEXPORT void Java_com_tns_Runtime_passExceptionToJsNative(JNIEnv* e v8::HandleScope handleScope(isolate); try { - runtime->PassExceptionToJsNative(env, obj, exception, message, stackTrace, isDiscarded); + runtime->PassExceptionToJsNative(env, obj, exception, message, fullStackTrace, jsStackTrace, isDiscarded); } catch (NativeScriptException& e) { e.ReThrowToJava(); } catch (std::exception e) { diff --git a/test-app/runtime/src/main/java/com/tns/Runtime.java b/test-app/runtime/src/main/java/com/tns/Runtime.java index 42d48d711..d3fbed7ab 100644 --- a/test-app/runtime/src/main/java/com/tns/Runtime.java +++ b/test-app/runtime/src/main/java/com/tns/Runtime.java @@ -58,7 +58,7 @@ private native void initNativeScript(int runtimeId, String filesPath, String nat private native void unlock(int runtimeId); - private native void passExceptionToJsNative(int runtimeId, Throwable ex, String message, String stackTrace, boolean isDiscarded); + private native void passExceptionToJsNative(int runtimeId, Throwable ex, String message, String fullStackTrace, String jsStackTrace, boolean isDiscarded); private native void clearStartupData(int runtimeId); @@ -78,15 +78,15 @@ private native void initNativeScript(int runtimeId, String filesPath, String nat private static native void ResetDateTimeConfigurationCache(int runtimeId); - void passUncaughtExceptionToJs(Throwable ex, String message, String stackTrace) { - passExceptionToJsNative(getRuntimeId(), ex, message, stackTrace, false); + void passUncaughtExceptionToJs(Throwable ex, String message, String fullStackTrace, String jsStackTrace) { + passExceptionToJsNative(getRuntimeId(), ex, message, fullStackTrace, jsStackTrace, false); } void passDiscardedExceptionToJs(Throwable ex, String prefix) { //String message = prefix + ex.getMessage(); // we'd better not prefix the error with something like - Error on "main" thread for reportSupressedException // as it doesn't seem very useful for the users - passExceptionToJsNative(getRuntimeId(), ex, ex.getMessage(), Runtime.getStackTraceErrorMessage(ex), true); + passExceptionToJsNative(getRuntimeId(), ex, ex.getMessage(), Runtime.getStackTraceErrorMessage(ex), Runtime.getJSStackTrace(ex), true); } public static void passSuppressedExceptionToJs(Throwable ex, String methodName) { @@ -274,6 +274,14 @@ private static String getStackTraceOnly(String content) { return result; } + public static String getJSStackTrace(Throwable ex) { + if (ex instanceof NativeScriptException) { + return ((NativeScriptException) ex).getIncomingStackTrace(); + } else { + return null; + } + } + public static String getStackTraceErrorMessage(Throwable ex) { String content; java.io.PrintStream ps = null; @@ -285,9 +293,10 @@ public static String getStackTraceErrorMessage(Throwable ex) { try { content = baos.toString("US-ASCII"); - if (ex instanceof NativeScriptException) { + String jsStackTrace = Runtime.getJSStackTrace(ex); + if (jsStackTrace != null) { content = getStackTraceOnly(content); - content = ((NativeScriptException) ex).getIncomingStackTrace() + content; + content = jsStackTrace + content; } } catch (java.io.UnsupportedEncodingException e) { content = e.getMessage();