From cf16739e7531231e686ca87ad711ded5048d6dae Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Thu, 27 Sep 2018 13:56:08 +0800 Subject: [PATCH] fix: catch some crash on ui thread --- .../mozilla/javascript/VMBridge_custom.java | 118 ++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java diff --git a/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java b/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java new file mode 100644 index 00000000..521b1084 --- /dev/null +++ b/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java @@ -0,0 +1,118 @@ +package org.mozilla.javascript; + +import android.os.Looper; +import android.util.Log; + +import org.mozilla.javascript.jdk15.VMBridge_jdk15; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class VMBridge_custom extends VMBridge_jdk15 { + + private static final String LOG_TAG = "VMBridge_custom"; + + public VMBridge_custom() throws SecurityException, InstantiationException { + } + + @Override + protected Object newInterfaceProxy(Object proxyHelper, ContextFactory cf, InterfaceAdapter adapter, Object target, Scriptable topScope) { + // --- The following code is copied from super class -- + Constructor c = (Constructor) proxyHelper; + InvocationHandler handler = (proxy, method, args) -> { + if (method.getDeclaringClass() == Object.class) { + String methodName = method.getName(); + if (methodName.equals("equals")) { + Object other = args[0]; + return proxy == other; + } + + if (methodName.equals("hashCode")) { + return target.hashCode(); + } + + if (methodName.equals("toString")) { + return "Proxy[" + target.toString() + "]"; + } + } + // Add thread check + //Check if the current thread is ui thread + if (Looper.myLooper() == Looper.getMainLooper()) { + // If so, catch any exception of invoking + // Because an exception on ui thread will cause the whole app to crash + try { + Object result = adapter.invoke(cf, target, topScope, proxy, method, args); + return castReturnValue(method, result); + } catch (Exception e) { + e.printStackTrace(); + // notify the script thread to exit + Object jsRuntime = topScope.get("runtime", null); + Log.d(LOG_TAG, "jsRuntime = " + jsRuntime); + if (jsRuntime instanceof NativeJavaObject) { + Object runtime = ((NativeJavaObject) jsRuntime).unwrap(); + Log.d(LOG_TAG, "runtime = " + runtime); + if(runtime instanceof com.stardust.autojs.runtime.ScriptRuntime){ + ((com.stardust.autojs.runtime.ScriptRuntime) runtime).exit(e); + } + } + // even if we caught the exception, we must return a value to for the method call. + return defaultValue(method.getReturnType()); + } + } else { + return castReturnValue(method, adapter.invoke(cf, target, topScope, proxy, method, args)); + } + }; + + // --- The following code is copied from super class -- + try { + Object proxy = c.newInstance(handler); + return proxy; + } catch (InvocationTargetException var10) { + throw Context.throwAsScriptRuntimeEx(var10); + } catch (IllegalAccessException var11) { + throw Kit.initCause(new IllegalStateException(), var11); + } catch (InstantiationException var12) { + throw Kit.initCause(new IllegalStateException(), var12); + } + } + + // cast the return value to boolean if needed. + // if a javascript function that implements a java interface returns nothing, + // it will be regarded as "false", like javascript behavior, instead of reporting error "undefined cannot be cast to boolean" + protected Object castReturnValue(Method method, Object returnValue) { + if (method.getReturnType().equals(Boolean.TYPE) || method.getReturnType().equals(Boolean.class)) { + return ScriptRuntime.toBoolean(returnValue); + } + return returnValue; + } + + protected Object defaultValue(Class type) { + if (type.equals(Boolean.TYPE) || type.equals(Boolean.class)) { + return false; + } + if (type.equals(Integer.TYPE) || type.equals(Integer.class)) { + return 0; + } + if (type.equals(Long.TYPE) || type.equals(Long.class)) { + return 0L; + } + if (type.equals(Float.TYPE) || type.equals(Float.class)) { + return 0F; + } + if (type.equals(Double.TYPE) || type.equals(Double.class)) { + return 0.0; + } + if (type.equals(Byte.TYPE) || type.equals(Byte.class)) { + return (byte) 0; + } + if (type.equals(Character.TYPE) || type.equals(Character.class)) { + return (char) 0; + } + if (type.isAssignableFrom(CharSequence.class)) { + return ""; + } + return null; + } +}