Skip to content

Commit 56fea06

Browse files
committedJan 22, 2015
resolved issue #40 Make possible to handle uncaught exception in JavaScript
1 parent 5720b87 commit 56fea06

13 files changed

+77
-160
lines changed
 

‎build/project-template/.classpath

-9
This file was deleted.

‎build/project-template/.project

-68
This file was deleted.

‎build/project-template/AndroidManifest.xml

-34
This file was deleted.

‎build/project-template/project.properties

-14
This file was deleted.

‎build/project-template/res/values/strings.xml

-5
This file was deleted.

‎build/project-template/res/values/styles.xml

-20
This file was deleted.

‎src/assets/app/bootstrap.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// A sample code how to catch uncaught errors
22
global.__onUncaughtError = function(error){
33
if(error.nativeException){
4-
// false == do not continue execution
4+
// false == do not continue executionW
5+
Log("ERROR.MESSAGE:---- " + error.message);
6+
Log("ERROR.STACK_TRACE:---- " + error.stackTrace);
7+
58
return false;
69
}
710

‎src/jni/ExceptionUtil.cpp

+23-9
Original file line numberDiff line numberDiff line change
@@ -159,23 +159,19 @@ void ExceptionUtil::OnUncaughtError(Handle<Message> message, Handle<Value> error
159159
auto isFunction = handler->IsFunction();
160160

161161
if(!isEmpty && isFunction){
162-
// call the global exception handler
163162
Handle<Value> errorObject;
164163

164+
//if the passed error is object
165165
if(error->IsObject()){
166+
//create exception object
166167
errorObject = error.As<Object>();
167-
error.As<Object>()->Set(ConvertToV8String("message"), ConvertToV8String(errorMessage));
168+
ExceptionUtil::SetMessageToErrorObject(errorMessage, errorObject);
168169
}
169170
else{
170-
errorObject = Exception::Error(ConvertToV8String(errorMessage));
171+
errorObject = Exception::Error(ConvertToV8String(errorMessage)); //get error object
171172
}
172173

173-
auto thiz = Object::New(isolate);
174-
auto func = handler.As<Function>();
175-
176-
// Notify the developer for the exception and let him do some additional job here
177-
// TODO: Launching UI at this point may be erroneous, think how to prevent it
178-
func->Call(thiz, 1, &errorObject);
174+
CalllFuncWithError(isolate, handler, errorObject);
179175

180176
// check whether the developer marked the error as "Caught"
181177
// As per discussion, it is safer to ALWAYS kill the application due to uncaught error(s)
@@ -189,6 +185,24 @@ void ExceptionUtil::OnUncaughtError(Handle<Message> message, Handle<Value> error
189185
//NativeScriptRuntime::APP_FAIL(errorMessage.c_str());
190186
}
191187

188+
void ExceptionUtil::SetMessageToErrorObject(const string &message, Handle<Value> errorObject){
189+
errorObject.As<Object>()->Set(ConvertToV8String("message"), ConvertToV8String(message));
190+
}
191+
192+
void ExceptionUtil::CalllFuncWithError(Isolate* isolate, Handle<Value> &handler, Handle<Value> errorObject){
193+
194+
if(!handler.IsEmpty() && handler->IsFunction())
195+
{
196+
auto func = handler.As<Function>();
197+
auto thiz = Object::New(isolate);
198+
func->Call(thiz, 1, &errorObject);
199+
}
200+
else
201+
{
202+
//throw exception, or fail in some way
203+
}
204+
}
205+
192206
string ExceptionUtil::GetErrorMessage(const Handle<Message>& message, const Handle<Value>& error){
193207
stringstream ss;
194208

‎src/jni/ExceptionUtil.h

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ namespace tns
4242
*/
4343
static void OnUncaughtError(v8::Handle<v8::Message> message, v8::Handle<v8::Value> error);
4444

45+
static void CalllFuncWithError(v8::Isolate* isolate, v8::Handle<v8::Value> &handler, v8::Handle<v8::Value> errorObject);
46+
4547
static ExceptionUtil* GetInstance();
4648

4749
private:
@@ -55,6 +57,8 @@ namespace tns
5557

5658
static ExceptionUtil* instance;
5759

60+
static void SetMessageToErrorObject(const std::string &message, v8::Handle<v8::Value> errorObject);
61+
5862
bool initialized;
5963

6064
JavaVM *jvm;

‎src/jni/V8StringConstants.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ namespace tns {
2525
return String::NewFromUtf8(Isolate::GetCurrent(), NATIVE_EXCEPTION.c_str());
2626
}
2727

28+
Local<String> V8StringConstants::GetStackTrace(){
29+
return String::NewFromUtf8(Isolate::GetCurrent(), STACK_TRACE.c_str());
30+
}
31+
2832
Local<String> V8StringConstants::GetLongNumber(){
2933
return String::NewFromUtf8(Isolate::GetCurrent(), LONG_NUMBER.c_str());
3034
}
@@ -99,6 +103,7 @@ namespace tns {
99103
const string V8StringConstants::EXTEND = "extend";
100104
const string V8StringConstants::IS_PROTOTYPE_IMPLEMENTATION_OBJECT = "__isPrototypeImplementationObject";
101105
const string V8StringConstants::NATIVE_EXCEPTION = "nativeException";
106+
const string V8StringConstants::STACK_TRACE = "stackTrace";
102107
const string V8StringConstants::LONG_NUMBER = "NativeScriptLongNumber";
103108
const string V8StringConstants::PROTOTYPE = "prototype";
104109
const string V8StringConstants::SUPER = "super";

‎src/jni/V8StringConstants.h

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace tns {
3333
static v8::Local<v8::String> GetExtends();
3434
static v8::Local<v8::String> GetIsPrototypeImplementationObject();
3535
static v8::Local<v8::String> GetNativeException();
36+
static v8::Local<v8::String> GetStackTrace();
3637
static v8::Local<v8::String> GetLongNumber();
3738
static v8::Local<v8::String> GetPrototype();
3839
static v8::Local<v8::String> GetSuper();
@@ -57,6 +58,7 @@ namespace tns {
5758
static const std::string EXTEND;
5859
static const std::string IS_PROTOTYPE_IMPLEMENTATION_OBJECT;
5960
static const std::string NATIVE_EXCEPTION;
61+
static const std::string STACK_TRACE;
6062
static const std::string LONG_NUMBER;
6163
static const std::string PROTOTYPE;
6264
static const std::string SUPER;

‎src/jni/com_tns_Platform.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "WeakRef.h"
1616
#include "NativeScriptAssert.h"
1717
#include "JsDebugger.h"
18+
#include "V8GlobalHelpers.h"
1819
#include <sstream>
1920
#include <android/log.h>
2021
#include <assert.h>
@@ -106,6 +107,7 @@ void PrepareV8Runtime(Isolate *isolate, JEnv& env, jstring filesPath, jstring pa
106107
V8::SetCaptureStackTraceForUncaughtExceptions(true, 100, StackTrace::kOverview);
107108
V8::AddMessageListener(ExceptionUtil::OnUncaughtError);
108109

110+
// says the New(); method will be deprecated soon and to use New(Isolate* isolate); instead
109111
auto globalTemplate = ObjectTemplate::New();
110112

111113
globalTemplate->Set(ConvertToV8String("__startNativeScriptProfiler"), FunctionTemplate::New(isolate, NativeScriptRuntime::StartProfilerCallback));
@@ -517,3 +519,34 @@ extern "C" void Java_com_tns_Platform_adjustAmountOfExternalAllocatedMemoryNativ
517519
{
518520
Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(usedMemory);
519521
}
522+
523+
extern "C" void Java_com_tns_Platform_passUncaughtExceptionToJsNative(JNIEnv *env, jobject obj, jthrowable javaException, jstring javaStackTrace)
524+
{
525+
Isolate* isolate = Isolate::GetCurrent();
526+
HandleScope handleScope(isolate);
527+
528+
auto context = isolate->GetCurrentContext();
529+
auto globalHandle = context->Global();
530+
auto handler = globalHandle->Get(V8StringConstants::GetUncaughtError());
531+
532+
//set up v8 exception objects
533+
auto message = "The application crashed because of an uncaught exception. You can look at the \"stackTrace\" or the \"nativeException\" for more information on the exception.";
534+
auto errObj = Exception::Error(ConvertToV8String(message)).As<Object>();
535+
536+
jint javaObjectID = objectManager->GetOrCreateObjectId((jobject) javaException);
537+
auto nativeExceptionObject = objectManager->GetJsObjectByJavaObject(javaObjectID);
538+
auto stackTrace = ArgConverter::jstringToV8String(javaStackTrace);
539+
540+
if (nativeExceptionObject.IsEmpty())
541+
{
542+
string className = objectManager->GetClassName((jobject)javaException);
543+
nativeExceptionObject = objectManager->CreateJSProxyInstance(javaObjectID, className);
544+
}
545+
546+
//fill error object with information about the uncaught exception
547+
errObj->Set(V8StringConstants::GetNativeException(), nativeExceptionObject);
548+
errObj->Set(V8StringConstants::GetStackTrace(), stackTrace);
549+
550+
//send to JS
551+
ExceptionUtil::GetInstance()->CalllFuncWithError(isolate, handler, errObj);
552+
}

‎src/src/com/tns/Platform.java

+6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public class Platform
4747

4848
private static native void adjustAmountOfExternalAllocatedMemoryNative(long changeInBytes);
4949

50+
private static native void passUncaughtExceptionToJsNative(Throwable ex, String javaStackTrace);
51+
5052
private static Context NativeScriptContext;
5153

5254
private static SparseArray<Object> strongInstances = new SparseArray<Object>();
@@ -162,6 +164,8 @@ public void uncaughtException(Thread thread, Throwable ex)
162164
{
163165
content = e.getMessage();
164166
}
167+
168+
passUncaughtExceptionToJsNative(ex, content);
165169
}
166170
finally
167171
{
@@ -187,6 +191,8 @@ public void run()
187191
{
188192
h.uncaughtException(thread, ex);
189193
}
194+
195+
//TODO: should we kill application when an uncaught exception is thrown?!
190196
}
191197
};
192198
}

0 commit comments

Comments
 (0)
Please sign in to comment.