From f1054283137a25d9eb31788092b0b12d1cc9d304 Mon Sep 17 00:00:00 2001 From: plamen5kov Date: Tue, 24 Mar 2015 14:30:59 +0200 Subject: [PATCH] error handling: -now the errors raise a pending intent and the app doesn't crash -refactored a bit --- src/jni/ArrayElementAccessor.cpp | 6 +-- src/jni/ExceptionUtil.cpp | 57 +++++++++----------- src/jni/ExceptionUtil.h | 8 +-- src/jni/MetadataNode.cpp | 22 +++----- src/jni/NativeScriptRuntime.cpp | 25 ++++----- src/jni/WeakRef.cpp | 6 +-- src/jni/com_tns_Platform.cpp | 42 ++++++++------- src/src/com/tns/ErrorReport.java | 46 ++++++++++++---- src/src/com/tns/NativeScriptApplication.java | 27 ++++------ src/src/com/tns/Platform.java | 17 +++--- test-app/assets/app/mainpage.js | 2 +- 11 files changed, 130 insertions(+), 128 deletions(-) diff --git a/src/jni/ArrayElementAccessor.cpp b/src/jni/ArrayElementAccessor.cpp index a54dafdcc..3edb67873 100644 --- a/src/jni/ArrayElementAccessor.cpp +++ b/src/jni/ArrayElementAccessor.cpp @@ -191,13 +191,13 @@ void ArrayElementAccessor::SetArrayElement(const Handle& array, uint32_t else { JsArgToArrayConverter::Error err = argConverter.GetError(); - ExceptionUtil::GetInstance()->HandleInvalidState(err.msg, false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(err.msg); return; } } else { - ExceptionUtil::GetInstance()->HandleInvalidState("Cannot assign primitive value to array of objects.", false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs("Cannot assign primitive value to array of objects."); return; } } @@ -217,7 +217,7 @@ Handle ArrayElementAccessor::CheckForArrayAccessException(JEnv& env, cons env.ExceptionClear(); string errMsg; ExceptionUtil::GetInstance()->GetExceptionMessage(env, exc, errMsg); - ExceptionUtil::GetInstance()->HandleInvalidState(errMsg, false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(errMsg); } else if (elementSignature == "Z") { diff --git a/src/jni/ExceptionUtil.cpp b/src/jni/ExceptionUtil.cpp index f7afc3916..1e08b51a9 100644 --- a/src/jni/ExceptionUtil.cpp +++ b/src/jni/ExceptionUtil.cpp @@ -115,36 +115,19 @@ void ExceptionUtil::GetExceptionMessage(JEnv& env, jthrowable exception, string& } } -void ExceptionUtil::HandleInvalidState(const string& message, bool fail){ - if(fail){ - NativeScriptRuntime::APP_FAIL(message.c_str()); - } - else { - auto error = Exception::Error(ConvertToV8String(message)); - Isolate::GetCurrent()->ThrowException(error); - } -} - -bool ExceptionUtil::HandleTryCatch(TryCatch& tc, bool rethrow){ +bool ExceptionUtil::HandleTryCatch(TryCatch& tc, const string& prependMessage){ if(!tc.HasCaught()){ return false; } - if(rethrow) - { - if(tc.CanContinue()){ - auto message = tc.Message(); - auto error = tc.Exception(); - OnUncaughtError(message, error); //calls JS global function("__onUncaughtError") passing the uncaught error - } - else { - auto errorMessage = PrintErrorMessage(tc.Message(), tc.Exception()); - - stringstream ss; - ss << "An uncaught error has occurred and V8's TryCatch block may not be continued. Error is: " << errorMessage; + if(tc.CanContinue()){ + ThrowExceptionToJava(tc, prependMessage); + } + else { + stringstream ss; + ss << endl << "An uncaught error has occurred and V8's TryCatch block may not be continued. Error is: "; - HandleInvalidState(ss.str(), true); - } + ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, ss.str()); } return true; @@ -206,12 +189,12 @@ string ExceptionUtil::GetErrorMessage(const Handle& message, const Hand str = String::NewFromUtf8(Isolate::GetCurrent(), ""); } String::Utf8Value utfError(str); - ss << *utfError << endl; + ss << endl << endl << *utfError << endl; ss << "File: \"" << ConvertToString(message->GetScriptResourceName().As()); - ss << ", line: " << message->GetLineNumber() - Constants::MODULE_LINES_OFFSET << ", column: " << message->GetStartColumn() << endl; + ss << ", line: " << message->GetLineNumber() - Constants::MODULE_LINES_OFFSET << ", column: " << message->GetStartColumn() << endl << endl; string stackTraceMessage = GetErrorStackTrace(message->GetStackTrace()); - ss << "StackTrace: " << endl << stackTraceMessage; + ss << "StackTrace: " << endl << stackTraceMessage << endl; return ss.str(); } @@ -258,18 +241,21 @@ string ExceptionUtil::GetErrorStackTrace(const Handle& stackTrace) return ss.str(); } -bool ExceptionUtil::ThrowExceptionToJava(TryCatch& tc) +bool ExceptionUtil::ThrowExceptionToJava(TryCatch& tc, const string& prependMessage) { Isolate *isolate = Isolate::GetCurrent(); auto ex = tc.Exception(); - string loggedMessage = PrintErrorMessage(tc.Message(), ex); + string message = PrintErrorMessage(tc.Message(), ex); + stringstream ss; + ss << endl << prependMessage << message; + string loggedMessage = ss.str(); DEBUG_WRITE("Error: %s", loggedMessage.c_str()); + JEnv env; + env.ExceptionClear(); if (tc.CanContinue()) { - JEnv env; - jweak javaThrowable = nullptr; if (ex->IsObject()) { @@ -303,6 +289,13 @@ bool ExceptionUtil::ThrowExceptionToJava(TryCatch& tc) } } +void ExceptionUtil::ThrowExceptionToJs(const string& exceptionMessage) +{ + Isolate *isolate(Isolate::GetCurrent()); + Local exception = v8::Exception::Error(ConvertToV8String(exceptionMessage)); + isolate->ThrowException(exception); +} + bool ExceptionUtil::CheckForJavaException(JEnv& env) { bool exceptionOccurred = env.ExceptionCheck() == JNI_TRUE; diff --git a/src/jni/ExceptionUtil.h b/src/jni/ExceptionUtil.h index c0d9b7e60..4d05c5a12 100644 --- a/src/jni/ExceptionUtil.h +++ b/src/jni/ExceptionUtil.h @@ -16,7 +16,9 @@ namespace tns bool CheckForJavaException(JEnv& env); - bool ThrowExceptionToJava(v8::TryCatch& tc); + bool ThrowExceptionToJava(v8::TryCatch& tc, const std::string& prependMessage = ""); + + void ThrowExceptionToJs(const std::string& exceptionMessage); void GetExceptionMessage(JEnv& env, jthrowable exception, std::string& errMsg); @@ -26,7 +28,7 @@ namespace tns * - The flow may continue. In this case a check for nested TryCatch blocks will be made and if such exist the error will be re-thrown. * - The flow may not continue. In this case a call the NativeScriptRuntime::APP_FAIL will be made. This will go to Java where the Java VM will be shut down. */ - bool HandleTryCatch(v8::TryCatch& tc, bool rethrow); + bool HandleTryCatch(v8::TryCatch& tc, const std::string& prependMessage = ""); /** * Provides an entry point to handle states considered invalid for the NativeScript runtime. @@ -34,7 +36,7 @@ namespace tns * - A state which does not break the whole runtime. In this case a JavaScript error will be raised. * - A state which breaks the runtime flow. In this case a call the NativeScriptRuntime::APP_FAIL will be made. This will go to Java where the Java VM will be shut down. */ - void HandleInvalidState(const std::string& message, bool fail); + void HandleInvalidState(const std::string& message); /** * A callback to the V8's AddMessageListener method. diff --git a/src/jni/MetadataNode.cpp b/src/jni/MetadataNode.cpp index ee2dcbc7b..2f13e1011 100644 --- a/src/jni/MetadataNode.cpp +++ b/src/jni/MetadataNode.cpp @@ -282,7 +282,7 @@ void MetadataNode::FieldAccessorSetterCallback(Local property,LocalThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage)))); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); } else { @@ -983,8 +983,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. No name specified for extend at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - Isolate *isolate(Isolate::GetCurrent()); - isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage)))); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); return false; } @@ -995,8 +994,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. No implementation object specified at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - Isolate *isolate(Isolate::GetCurrent()); - isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage)))); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); return false; } @@ -1010,8 +1008,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. No name for extend specified at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - Isolate *isolate(Isolate::GetCurrent()); - isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage)))); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); return false; } @@ -1021,8 +1018,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. Named extend should be called with second object parameter containing overridden methods at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - Isolate *isolate(Isolate::GetCurrent()); - isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage)))); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); return false; } @@ -1035,8 +1031,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "The extend name \"" << ConvertToString(extendName) << "\" you provided contains invalid symbols. Try using the symbols [a-z, A-Z, 0-9, _]." << endl; string exceptionMessage = ss.str(); - Isolate *isolate(Isolate::GetCurrent()); - isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage)))); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); return false; } implementationObject = info[1]->ToObject(); @@ -1047,8 +1042,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - Isolate *isolate(Isolate::GetCurrent()); - isolate->ThrowException(v8::Exception::Error((ConvertToV8String(exceptionMessage)))); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); return false; } @@ -1111,7 +1105,7 @@ void MetadataNode::ExtendCallMethodHandler(const v8::FunctionCallbackInfoHandleInvalidState(s.str(), false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(s.str()); return; } diff --git a/src/jni/NativeScriptRuntime.cpp b/src/jni/NativeScriptRuntime.cpp index 5004cb850..718035356 100644 --- a/src/jni/NativeScriptRuntime.cpp +++ b/src/jni/NativeScriptRuntime.cpp @@ -192,7 +192,7 @@ void NativeScriptRuntime::CallJavaMethod(const Handle& caller, const str if (!argConverter.IsValid()) { JsArgConverter::Error err = argConverter.GetError(); - ExceptionUtil::GetInstance()->HandleInvalidState(err.msg, false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(err.msg); return; } @@ -624,7 +624,7 @@ jobject NativeScriptRuntime::CreateJavaInstance(int objectID, const std::string& else { JsArgToArrayConverter::Error err = argConverter.GetError(); - ExceptionUtil::GetInstance()->HandleInvalidState(err.msg, false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(err.msg); } return instance; @@ -819,7 +819,7 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfoHandleInvalidState(exception, false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception); return; } if (modulePath == "EXTERNAL_FILE_ERROR") @@ -828,7 +828,7 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfoHandleInvalidState(exception, false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception); return; } @@ -851,7 +851,7 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo()); DEBUG_WRITE("Compiled script (module %s)", moduleName.c_str()); - if(ExceptionUtil::GetInstance()->HandleTryCatch(tc, true)){ + if(ExceptionUtil::GetInstance()->HandleTryCatch(tc)){ loadedModules.erase(modulePath); tmpExportObj->Reset(); delete tmpExportObj; @@ -869,12 +869,11 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfoHandleTryCatch(tcRequire, true)){ + if(ExceptionUtil::GetInstance()->HandleTryCatch(tcRequire)){ loadedModules.erase(modulePath); tmpExportObj->Reset(); delete tmpExportObj; hasError = true; - tcRequire.ReThrow(); } else { if (moduleObj.IsEmpty()) @@ -897,11 +896,6 @@ void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const HandleHandleInvalidState(ss.str(), false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(ss.str()); result = Undefined(isolate); } @@ -1038,7 +1032,7 @@ Handle NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const HandleHandleInvalidState(ss.str(), false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs(ss.str()); result = Undefined(isolate); } @@ -1062,8 +1056,7 @@ Handle NativeScriptRuntime::CallJSMethod(JNIEnv *_env, const HandleHandleTryCatch(tc, true); - if (exceptionFound) + if (tc.HasCaught()) { jsResult = Undefined(isolate); } diff --git a/src/jni/WeakRef.cpp b/src/jni/WeakRef.cpp index e215f1897..ca4a446b4 100644 --- a/src/jni/WeakRef.cpp +++ b/src/jni/WeakRef.cpp @@ -42,17 +42,17 @@ void WeakRef::ConstructorCallback(const FunctionCallbackInfo& args) } else { - ExceptionUtil::GetInstance()->HandleInvalidState("The WeakRef constructor expects an object argument.", false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs("The WeakRef constructor expects an object argument."); } } else { - ExceptionUtil::GetInstance()->HandleInvalidState("The WeakRef constructor expects single parameter.", false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs("The WeakRef constructor expects single parameter."); } } else { - ExceptionUtil::GetInstance()->HandleInvalidState("WeakRef must be used as a construct call.", false); + ExceptionUtil::GetInstance()->ThrowExceptionToJs("WeakRef must be used as a construct call."); } } diff --git a/src/jni/com_tns_Platform.cpp b/src/jni/com_tns_Platform.cpp index 850d841c9..ab54e4745 100644 --- a/src/jni/com_tns_Platform.cpp +++ b/src/jni/com_tns_Platform.cpp @@ -93,7 +93,7 @@ void PrepareExtendFunction(Isolate *isolate, jstring filesPath) script->Run(); - ExceptionUtil::GetInstance()->HandleTryCatch(tc, true); + ExceptionUtil::GetInstance()->HandleTryCatch(tc); DEBUG_WRITE("Executed prepareExtend.js script"); } @@ -205,13 +205,13 @@ extern "C" void Java_com_tns_Platform_runNativeScript(JNIEnv *_env, jobject obj, DEBUG_WRITE("Compile script"); - if (ExceptionUtil::GetInstance()->HandleTryCatch(tc, true)) + if (ExceptionUtil::GetInstance()->HandleTryCatch(tc, "Bootstrap script has error(s).")) { - ExceptionUtil::GetInstance()->HandleInvalidState("Bootstrap script has error(s).", true); + DEBUG_WRITE("Exception was handled in java code"); } else if (script.IsEmpty()) { - ExceptionUtil::GetInstance()->HandleInvalidState("Bootstrap script is empty.", true); + DEBUG_WRITE("Bootstrap was empty"); } else { @@ -225,9 +225,9 @@ extern "C" void Java_com_tns_Platform_runNativeScript(JNIEnv *_env, jobject obj, } auto appModuleObj = script->Run(); - if (ExceptionUtil::GetInstance()->HandleTryCatch(tc, true)) + if (ExceptionUtil::GetInstance()->HandleTryCatch(tc)) { - // TODO: Fail? + DEBUG_WRITE("Exception was handled in java code"); } else if (!appModuleObj.IsEmpty() && appModuleObj->IsFunction()) { @@ -236,9 +236,9 @@ extern "C" void Java_com_tns_Platform_runNativeScript(JNIEnv *_env, jobject obj, auto thiz = Object::New(isolate); auto res = moduleFunc->Call(thiz, 1, &exportsObj); - if(ExceptionUtil::GetInstance()->HandleTryCatch(tc, false)) + if(ExceptionUtil::GetInstance()->HandleTryCatch(tc)) { - ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc); + DEBUG_WRITE("Exception was handled in java code"); } else { @@ -248,7 +248,7 @@ extern "C" void Java_com_tns_Platform_runNativeScript(JNIEnv *_env, jobject obj, } else { - ExceptionUtil::GetInstance()->HandleInvalidState("Error running NativeScript bootstrap code.", true); + ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "Error running NativeScript bootstrap code."); } } @@ -307,6 +307,7 @@ jobject ConvertJsValueToJavaObject(JEnv& env, const Handle& value) extern "C" jobject Java_com_tns_Platform_callJSMethodNative(JNIEnv *_env, jobject obj, jint javaObjectID, jstring methodName, jboolean isConstructor, jobjectArray packagedArgs) { JEnv env(_env); + TryCatch tc; DEBUG_WRITE("CallJSMethodNative called javaObjectID=%d", javaObjectID); @@ -321,7 +322,7 @@ extern "C" jobject Java_com_tns_Platform_callJSMethodNative(JNIEnv *_env, jobjec ss << "Attempting to call method " << ArgConverter::jstringToString(methodName) << endl; // TODO: Should we kill the Java VM here? - ExceptionUtil::GetInstance()->HandleInvalidState(ss.str(), true); + ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, ss.str()); return nullptr; } @@ -336,13 +337,14 @@ extern "C" jobject Java_com_tns_Platform_callJSMethodNative(JNIEnv *_env, jobjec string method_name = ArgConverter::jstringToString(methodName); - TryCatch tc; auto jsResult = NativeScriptRuntime::CallJSMethod(env, jsObject, methodName, packagedArgs, tc); - if (tc.HasCaught()) + stringstream ss; + ss << "Calling js method " << method_name << " failed"; + string exceptionMessage = ss.str(); + if (ExceptionUtil::GetInstance()->HandleTryCatch(tc, exceptionMessage)) { - DEBUG_WRITE("Calling js method %s failed", method_name.c_str()); - ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc); + DEBUG_WRITE(exceptionMessage.c_str()); } jobject javaObject = ConvertJsValueToJavaObject(env, jsResult); @@ -358,7 +360,7 @@ extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_en auto isolate = Isolate::GetCurrent(); HandleScope handleScope(isolate); // TODO: Do we need a TryCatch here? It is currently not used anywhere - // TryCatch tc; + TryCatch tc; string existingClassName = ArgConverter::jstringToString(className); string jniName = Util::ConvertFromCanonicalToJniName(existingClassName); @@ -372,7 +374,7 @@ extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_en auto appInstance = objectManager->GetJsObjectByJavaObject(AppJavaObjectID); if (appInstance.IsEmpty()) { - ExceptionUtil::GetInstance()->HandleInvalidState("NativeScript application not initialized correctly. Missing the global app object initialization.", true); + ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. Missing the global app object initialization."); return nullptr; } @@ -381,7 +383,7 @@ extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_en if (createActivityFunction.IsEmpty() || !createActivityFunction->IsFunction()) { - ExceptionUtil::GetInstance()->HandleInvalidState("NativeScript application not initialized correctly. No function 'createActivity' found on the application object.", true); + ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. No function 'createActivity' found on the application object."); return nullptr; } @@ -391,7 +393,7 @@ extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_en jsInstance = jsResult.As(); if (jsInstance.IsEmpty() || jsInstance->IsNull() || jsInstance->IsUndefined()) { - ExceptionUtil::GetInstance()->HandleInvalidState("NativeScript application not initialized correctly. getActivity method returned invalid value.", true); + ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. getActivity method returned invalid value."); return nullptr; } @@ -401,7 +403,7 @@ extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_en // // if (nodeName != jniName) // { -// ExceptionUtil::GetInstance()->HandleInvalidState("NativeScript application not initialized correctly. createActivity returned wrong type.", true); +// ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. createActivity returned wrong type."); // return nullptr; // } } @@ -412,7 +414,7 @@ extern "C" jobjectArray Java_com_tns_Platform_createJSInstanceNative(JNIEnv *_en jsInstance = MetadataNode::CreateExtendedJSWrapper(isolate, proxyClassName); if (jsInstance.IsEmpty()) { - ExceptionUtil::GetInstance()->HandleInvalidState("NativeScript application not initialized correctly. Cannot create extended JS wrapper.", true); + ExceptionUtil::GetInstance()->ThrowExceptionToJava(tc, "NativeScript application not initialized correctly. Cannot create extended JS wrapper."); return nullptr; } } diff --git a/src/src/com/tns/ErrorReport.java b/src/src/com/tns/ErrorReport.java index 308483dbc..38c33786a 100644 --- a/src/src/com/tns/ErrorReport.java +++ b/src/src/com/tns/ErrorReport.java @@ -7,6 +7,8 @@ import java.io.UnsupportedEncodingException; import android.app.Activity; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; import android.graphics.drawable.GradientDrawable; @@ -28,26 +30,50 @@ public ErrorReport(Activity activity) this.activity = activity; } - static void startActivity(final Context context, Throwable ex) + static boolean startActivity(final Context context, Throwable ex) { String errorDetailedMessage = getErrorMessage(ex); final String errMsg = errorDetailedMessage; - final Intent intent = getIntent(context, errMsg); + final Intent intent = getIntent(context, errMsg); + if(intent == null) { - return; //(if in release mode) don't do anything + return false; //(if in release mode) don't do anything } CreateErrorFile(context); - new Thread() { - @Override - public void run() - { - context.startActivity(intent); - } - }.start(); + startPendingErrorActivity(context, intent); + + killProcess(context); + + return true; + } + + static void killProcess(Context context) + { + // finish current activity and all below it first + if (context instanceof Activity) { + ((Activity)context).finishAffinity(); + } + + //kill process + android.os.Process.killProcess(android.os.Process.myPid()); + } + + static void startPendingErrorActivity(Context context, Intent intent) + { + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); + + try + { + pendingIntent.send(context, 0, intent); + } + catch (CanceledException e) + { + if (Platform.IsLogEnabled) Log.e(Platform.DEFAULT_LOG_TAG, "Couldn't send pending intent! Exception: " + e.getMessage()); + } } static String getErrorMessage(Throwable ex) diff --git a/src/src/com/tns/NativeScriptApplication.java b/src/src/com/tns/NativeScriptApplication.java index 0943948c1..afc6629d7 100644 --- a/src/src/com/tns/NativeScriptApplication.java +++ b/src/src/com/tns/NativeScriptApplication.java @@ -724,25 +724,18 @@ public void onCreate() { if (!showErrorIntent) { appInstance = this; - try - { - prepareAppBuilderCallbackImpl(); - - if (appBuilderCallbackImpl != null) - { - appBuilderCallbackImpl.onCreate(this); - } - - Platform.init(this); - Platform.run(Platform.DefaultApplicationModuleName); - - onCreateInternal(); - } - catch (Throwable ex) + + prepareAppBuilderCallbackImpl(); + + if (appBuilderCallbackImpl != null) { - ErrorReport.HasApplicationCreateError = true; - ErrorReport.startActivity(this, ex); + appBuilderCallbackImpl.onCreate(this); } + + Platform.init(this); + Platform.run(Platform.DefaultApplicationModuleName); + + onCreateInternal(); } } diff --git a/src/src/com/tns/Platform.java b/src/src/com/tns/Platform.java index 03bc85aa7..c6999fbc9 100644 --- a/src/src/com/tns/Platform.java +++ b/src/src/com/tns/Platform.java @@ -16,7 +16,6 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; -import java.util.zip.ZipEntry; import android.app.Activity; import android.content.Context; @@ -151,26 +150,26 @@ public static void disableVerboseLogging() static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler) { + final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + if (handler == null) { - final UncaughtExceptionHandler h = Thread.getDefaultUncaughtExceptionHandler(); - handler = new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, Throwable ex) { - ErrorReport.startActivity(NativeScriptContext, ex); - String content = ErrorReport.getErrorMessage(ex); passUncaughtExceptionToJsNative(ex, content); - + if (IsLogEnabled) Log.e(DEFAULT_LOG_TAG, "Uncaught Exception Message=" + ex.getMessage()); - // call the already installed handler (if any) - if (h != null) + //start error activity + boolean errorActivityHasStarted = ErrorReport.startActivity(NativeScriptContext, ex); + + if(!errorActivityHasStarted && defaultHandler != null) //if we are in release mode { - h.uncaughtException(thread, ex); + defaultHandler.uncaughtException(thread, ex); } } }; diff --git a/test-app/assets/app/mainpage.js b/test-app/assets/app/mainpage.js index f10de4341..92651a056 100644 --- a/test-app/assets/app/mainpage.js +++ b/test-app/assets/app/mainpage.js @@ -57,7 +57,7 @@ var MainActivity = (function (_super) { _super.prototype.onCreate.call(this, null); //this.super.onCreate(null); - //require("./tests/testsWithContext").run(this); + require("./tests/testsWithContext").run(this); var layout = new android.widget.LinearLayout(this); layout.setOrientation(1);