fix: app crash when ui script throws exception

This commit is contained in:
hyb1996
2017-11-07 12:56:19 +08:00
parent 7c1decdc04
commit d3c60049b7
8 changed files with 77 additions and 16 deletions

View File

@@ -10,7 +10,9 @@ module.exports = function(__runtime__, scope){
ui.setContentView = function(view){ ui.setContentView = function(view){
ui.view = view; ui.view = view;
ui.__view_cache__ = {}; ui.__view_cache__ = {};
ui.run(function(){
activity.setContentView(view); activity.setContentView(view);
});
} }
ui.id = function(id){ ui.id = function(id){
@@ -43,12 +45,16 @@ module.exports = function(__runtime__, scope){
color = android.graphics.Color.parseColor(color); color = android.graphics.Color.parseColor(color);
} }
if(android.os.Build.VERSION.SDK_INT >= 21){ if(android.os.Build.VERSION.SDK_INT >= 21){
ui.run(function(){
activity.getWindow().setStatusBarColor(color); activity.getWindow().setStatusBarColor(color);
});
} }
} }
ui.finish = function(){ ui.finish = function(){
ui.run(function(){
activity.finish(); activity.finish();
});
} }
ui.findViewByStringId = function(view, id){ ui.findViewByStringId = function(view, id){
@@ -97,5 +103,7 @@ module.exports = function(__runtime__, scope){
return ui[name]; return ui[name];
} }
}; };
return proxy; return proxy;
} }

View File

@@ -11,6 +11,9 @@ import com.stardust.autojs.core.ui.widget.JsFrameLayout;
import com.stardust.autojs.core.ui.xml.XmlConverter; import com.stardust.autojs.core.ui.xml.XmlConverter;
import com.stardust.util.MapEntries; import com.stardust.util.MapEntries;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map; import java.util.Map;
/** /**
@@ -54,7 +57,6 @@ public class ConvertLayoutInflater implements JsLayoutInflater {
@Override @Override
public View inflate(Context context, String xml) { public View inflate(Context context, String xml) {
try { try {
String androidLayoutXml = XmlConverter.convertToAndroidLayout(xml); String androidLayoutXml = XmlConverter.convertToAndroidLayout(xml);
JsFrameLayout root = new JsFrameLayout(context); JsFrameLayout root = new JsFrameLayout(context);

View File

@@ -16,6 +16,12 @@ import com.stardust.util.Callback;
public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine { public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
public interface ExecuteCallback {
void onResult(Object r);
void onException(Exception e);
}
private Handler mHandler; private Handler mHandler;
private boolean mLooping = false; private boolean mLooping = false;
@@ -30,15 +36,21 @@ public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
} }
public void execute(final ScriptSource source, final Callback<Object> callback) { public void execute(final ScriptSource source, final ExecuteCallback callback) {
Runnable r = new Runnable() { Runnable r = () -> {
@Override try {
public void run() {
Object o = LoopBasedJavaScriptEngine.super.execute((JavaScriptSource) source); Object o = LoopBasedJavaScriptEngine.super.execute((JavaScriptSource) source);
if (callback != null) if (callback != null)
callback.call(o); callback.onResult(o);
} catch (Exception e) {
if (callback == null) {
throw e;
} else {
callback.onException(e);
} }
}
}; };
mHandler.post(r); mHandler.post(r);
if (!mLooping && Looper.myLooper() != Looper.getMainLooper()) { if (!mLooping && Looper.myLooper() != Looper.getMainLooper()) {
@@ -56,7 +68,9 @@ public class LoopBasedJavaScriptEngine extends RhinoJavaScriptEngine {
@Override @Override
public synchronized void destroy() { public synchronized void destroy() {
Loopers.quitForThread(getThread()); Thread thread = getThread();
if (thread != null)
Loopers.quitForThread(thread);
super.destroy(); super.destroy();
} }

View File

@@ -13,6 +13,7 @@ import com.stardust.automator.UiObjectCollection;
import com.stardust.pio.PFiles; import com.stardust.pio.PFiles;
import com.stardust.pio.UncheckedIOException; import com.stardust.pio.UncheckedIOException;
import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context; import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory; import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.ImporterTopLevel;
@@ -43,6 +44,7 @@ import java.util.Locale;
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> mExceptionHandlerThreadLocal = new ThreadLocal<>();
private static int contextCount = 0; private static int contextCount = 0;
private static StringScriptSource sInitScript; private static StringScriptSource sInitScript;
@@ -163,6 +165,10 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
return context; return context;
} }
public static void setUncaghtExceptionHandler(Thread.UncaughtExceptionHandler handler) {
mExceptionHandlerThreadLocal.set(handler);
}
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) {
@@ -196,6 +202,21 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
cx.setInstructionObserverThreshold(10000); cx.setInstructionObserverThreshold(10000);
return cx; return cx;
} }
@Override
protected Object doTopCall(Callable callable, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
Thread.UncaughtExceptionHandler exceptionHandler = mExceptionHandlerThreadLocal.get();
if (exceptionHandler == null)
return super.doTopCall(callable, cx, scope, thisObj, args);
else {
try {
return super.doTopCall(callable, cx, scope, thisObj, args);
} catch (Exception e) {
exceptionHandler.uncaughtException(Thread.currentThread(), e);
return null;
}
}
}
} }

View File

@@ -5,16 +5,20 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import com.stardust.autojs.engine.LoopBasedJavaScriptEngine;
import com.stardust.autojs.engine.RhinoJavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine; import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.engine.ScriptEngineManager; import com.stardust.autojs.engine.ScriptEngineManager;
import com.stardust.autojs.script.JavaScriptSource;
import com.stardust.autojs.script.ScriptSource; import com.stardust.autojs.script.ScriptSource;
import com.stardust.lang.ThreadCompat;
import com.stardust.util.IntentExtras; import com.stardust.util.IntentExtras;
/** /**
* Created by Stardust on 2017/2/5. * Created by Stardust on 2017/2/5.
*/ */
public class ScriptExecuteActivity extends AppCompatActivity { public class ScriptExecuteActivity extends AppCompatActivity implements Thread.UncaughtExceptionHandler {
private static final String EXTRA_EXECUTION = ScriptExecuteActivity.class.getName() + ".execution"; private static final String EXTRA_EXECUTION = ScriptExecuteActivity.class.getName() + ".execution";
@@ -47,6 +51,7 @@ public class ScriptExecuteActivity extends AppCompatActivity {
mScriptSource = mScriptExecution.getSource(); mScriptSource = mScriptExecution.getSource();
mScriptEngine = mScriptExecution.getEngine(); mScriptEngine = mScriptExecution.getEngine();
mExecutionListener = mScriptExecution.getListener(); mExecutionListener = mScriptExecution.getListener();
RhinoJavaScriptEngine.setUncaghtExceptionHandler(this);
runScript(); runScript();
} }
@@ -60,6 +65,7 @@ public class ScriptExecuteActivity extends AppCompatActivity {
} }
} }
@SuppressWarnings("unchecked")
private void doExecution() { private void doExecution() {
mScriptEngine.setTag(ScriptEngine.TAG_SOURCE, mScriptSource); mScriptEngine.setTag(ScriptEngine.TAG_SOURCE, mScriptSource);
mExecutionListener.onStart(mScriptExecution); mExecutionListener.onStart(mScriptExecution);
@@ -86,6 +92,12 @@ public class ScriptExecuteActivity extends AppCompatActivity {
mScriptExecution = null; mScriptExecution = null;
} }
@Override
public void uncaughtException(Thread t, Throwable e) {
mExecutionListener.onException(mScriptExecution, (Exception) e);
super.finish();
}
private static class ActivityScriptExecution extends ScriptExecution.AbstractScriptExecution { private static class ActivityScriptExecution extends ScriptExecution.AbstractScriptExecution {
private ScriptEngine mScriptEngine; private ScriptEngine mScriptEngine;

View File

@@ -50,4 +50,5 @@ public class AndroidContextFactory extends ShellContextFactory {
return cx; return cx;
} }
} }

View File

@@ -51,4 +51,6 @@ public class UI extends ProxyObject {
} }
} }

View File

@@ -35,6 +35,7 @@ import com.stardust.util.ScreenMetrics;
import com.stardust.util.Supplier; import com.stardust.util.Supplier;
import com.stardust.util.UiHandler; import com.stardust.util.UiHandler;
import com.stardust.view.accessibility.AccessibilityInfoProvider; import com.stardust.view.accessibility.AccessibilityInfoProvider;
import com.stardust.view.accessibility.AccessibilityNotificationObserver;
import com.stardust.view.accessibility.AccessibilityService; import com.stardust.view.accessibility.AccessibilityService;
import com.stardust.view.accessibility.AccessibilityServiceUtils; import com.stardust.view.accessibility.AccessibilityServiceUtils;
import com.stardust.view.accessibility.NotificationListener; import com.stardust.view.accessibility.NotificationListener;
@@ -58,7 +59,7 @@ public class AutoJs {
} }
private final AccessibilityActionRecorder mAccessibilityActionRecorder = new AccessibilityActionRecorder(); private final AccessibilityActionRecorder mAccessibilityActionRecorder = new AccessibilityActionRecorder();
private final NotificationListener.AccessibilityNotificationObserver mNotificationObserver; private final AccessibilityNotificationObserver mNotificationObserver;
private ScriptEngineManager mScriptEngineManager; private ScriptEngineManager mScriptEngineManager;
private final Context mContext; private final Context mContext;
private final UiHandler mUiHandler; private final UiHandler mUiHandler;
@@ -74,7 +75,7 @@ public class AutoJs {
mUiHandler = new UiHandler(context); mUiHandler = new UiHandler(context);
mAppUtils = new AppUtils(context); mAppUtils = new AppUtils(context);
mGlobalConsole = new GlobalStardustConsole(mUiHandler); mGlobalConsole = new GlobalStardustConsole(mUiHandler);
mNotificationObserver = new NotificationListener.AccessibilityNotificationObserver(context); mNotificationObserver = new AccessibilityNotificationObserver(context);
mAccessibilityInfoProvider = new AccessibilityInfoProvider(context.getPackageManager()); mAccessibilityInfoProvider = new AccessibilityInfoProvider(context.getPackageManager());
mScriptEngineService = buildScriptEngineService(); mScriptEngineService = buildScriptEngineService();
addAccessibilityServiceDelegates(); addAccessibilityServiceDelegates();
@@ -198,7 +199,7 @@ public class AutoJs {
} }
@Override @Override
public NotificationListener.AccessibilityNotificationObserver getNotificationObserver() { public AccessibilityNotificationObserver getNotificationObserver() {
return mNotificationObserver; return mNotificationObserver;
} }