fix: crash when a exception is thrown by script on ui thread

This commit is contained in:
hyb1996
2017-12-30 00:22:01 +08:00
parent e8e73aac14
commit f39516a4b4
3 changed files with 28 additions and 17 deletions

View File

@@ -1,9 +1,10 @@
package com.stardust.autojs.engine; package com.stardust.autojs.engine;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.widget.TextView;
import com.stardust.autojs.BuildConfig; import com.stardust.autojs.BuildConfig;
import com.stardust.autojs.execution.ScriptExecutionListener;
import com.stardust.autojs.rhino.AndroidContextFactory; import com.stardust.autojs.rhino.AndroidContextFactory;
import com.stardust.autojs.rhino.RhinoAndroidHelper; import com.stardust.autojs.rhino.RhinoAndroidHelper;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
@@ -34,10 +35,9 @@ import java.util.Locale;
* Created by Stardust on 2017/4/2. * Created by Stardust on 2017/4/2.
*/ */
public class RhinoJavaScriptEngine extends JavaScriptEngine { public class RhinoJavaScriptEngine extends JavaScriptEngine {
private static final String LOG_TAG = "RhinoJavaScriptEngine"; private static final String LOG_TAG = "RhinoJavaScriptEngine";
private static ThreadLocal<Thread.UncaughtExceptionHandler> sExceptionHandlerThreadLocal = new ThreadLocal<>();
private static int contextCount = 0; private static int contextCount = 0;
private static StringScriptSource sInitScript; private static StringScriptSource sInitScript;
@@ -47,6 +47,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
private Scriptable mScriptable; private Scriptable mScriptable;
private Thread mThread; private Thread mThread;
private android.content.Context mAndroidContext; private android.content.Context mAndroidContext;
private Thread.UncaughtExceptionHandler mUiThreadExceptionHandler;
public RhinoJavaScriptEngine(android.content.Context context) { public RhinoJavaScriptEngine(android.content.Context context) {
mAndroidContext = context; mAndroidContext = context;
@@ -147,23 +148,28 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
} }
public Context createContext() { public Context createContext() {
if (!ContextFactory.hasExplicitGlobal()) { // if (!ContextFactory.hasExplicitGlobal()) {
ContextFactory.initGlobal(new InterruptibleAndroidContextFactory(new File(mAndroidContext.getCacheDir(), "classes"))); // ContextFactory.initGlobal(new InterruptibleAndroidContextFactory(new File(mAndroidContext.getCacheDir(), "classes")));
} //}
Context context = new RhinoAndroidHelper(mAndroidContext).enterContext(); Context context = new InterruptibleAndroidContextFactory(new File(mAndroidContext.getCacheDir(), "classes")).enterContext();//new RhinoAndroidHelper(mAndroidContext).enterContext();
contextCount++; contextCount++;
setupContext(context);
return context;
}
protected void setupContext(Context context) {
context.setOptimizationLevel(-1); context.setOptimizationLevel(-1);
context.setLanguageVersion(Context.VERSION_ES6); context.setLanguageVersion(Context.VERSION_ES6);
context.setLocale(Locale.getDefault()); context.setLocale(Locale.getDefault());
context.setWrapFactory(new WrapFactory()); context.setWrapFactory(new WrapFactory());
return context;
} }
public static void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler handler) { public void setUiThreadExceptionHandler(Thread.UncaughtExceptionHandler uiThreadExceptionHandler) {
sExceptionHandlerThreadLocal.set(handler); mUiThreadExceptionHandler = uiThreadExceptionHandler;
} }
private class WrapFactory extends org.mozilla.javascript.WrapFactory { private class WrapFactory extends org.mozilla.javascript.WrapFactory {
@Override @Override
public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType) { public Object wrap(Context cx, Scriptable scope, Object obj, Class<?> staticType) {
if (obj instanceof String) { if (obj instanceof String) {
@@ -175,14 +181,16 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
} }
return super.wrap(cx, scope, obj, staticType); return super.wrap(cx, scope, obj, staticType);
} }
} }
private static class InterruptibleAndroidContextFactory extends AndroidContextFactory { private class InterruptibleAndroidContextFactory extends AndroidContextFactory {
public InterruptibleAndroidContextFactory(File cacheDirectory) { public InterruptibleAndroidContextFactory(File cacheDirectory) {
super(cacheDirectory); super(cacheDirectory);
} }
@Override @Override
protected void observeInstructionCount(Context cx, int instructionCount) { protected void observeInstructionCount(Context cx, int instructionCount) {
if (Thread.currentThread().isInterrupted()) { if (Thread.currentThread().isInterrupted()) {
@@ -199,17 +207,15 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
@Override @Override
protected Object doTopCall(Callable callable, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { protected Object doTopCall(Callable callable, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
Thread.UncaughtExceptionHandler exceptionHandler = sExceptionHandlerThreadLocal.get(); if (Looper.myLooper() == Looper.getMainLooper()) {
if (exceptionHandler == null)
return super.doTopCall(callable, cx, scope, thisObj, args);
else {
try { try {
return super.doTopCall(callable, cx, scope, thisObj, args); return super.doTopCall(callable, cx, scope, thisObj, args);
} catch (Exception e) { } catch (Exception e) {
exceptionHandler.uncaughtException(Thread.currentThread(), e); mUiThreadExceptionHandler.uncaughtException(Thread.currentThread(), e);
return null; return null;
} }
} }
return super.doTopCall(callable, cx, scope, thisObj, args);
} }
} }

View File

@@ -23,6 +23,10 @@ public class LoopedBasedJavaScriptExecution extends RunnableScriptExecution {
long delay = getConfig().delay; long delay = getConfig().delay;
sleep(delay); sleep(delay);
final LoopBasedJavaScriptEngine javaScriptEngine = (LoopBasedJavaScriptEngine) engine; final LoopBasedJavaScriptEngine javaScriptEngine = (LoopBasedJavaScriptEngine) engine;
javaScriptEngine.setUiThreadExceptionHandler((t, e) -> {
javaScriptEngine.forceStop();
getListener().onException(this, (Exception) e);
});
final long interval = getConfig().interval; final long interval = getConfig().interval;
javaScriptEngine.getRuntime().loopers.setMainLooperQuitHandler(new Loopers.LooperQuitHandler() { javaScriptEngine.getRuntime().loopers.setMainLooperQuitHandler(new Loopers.LooperQuitHandler() {
long times = getConfig().loopTimes == 0 ? Integer.MAX_VALUE : getConfig().loopTimes; long times = getConfig().loopTimes == 0 ? Integer.MAX_VALUE : getConfig().loopTimes;

View File

@@ -49,7 +49,7 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U
mScriptSource = mScriptExecution.getSource(); mScriptSource = mScriptExecution.getSource();
mScriptEngine = mScriptExecution.getEngine(); mScriptEngine = mScriptExecution.getEngine();
mExecutionListener = mScriptExecution.getListener(); mExecutionListener = mScriptExecution.getListener();
RhinoJavaScriptEngine.setUncaughtExceptionHandler(this); ((RhinoJavaScriptEngine) mScriptEngine).setUiThreadExceptionHandler((t, e) -> onException((Exception) e));
runScript(); runScript();
} }
@@ -119,6 +119,7 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U
mScriptEngineManager = manager; mScriptEngineManager = manager;
} }
@Override @Override
public ScriptEngine getEngine() { public ScriptEngine getEngine() {
if (mScriptEngine == null) { if (mScriptEngine == null) {