diff --git a/app/src/main/java/com/stardust/scriptdroid/App.java b/app/src/main/java/com/stardust/scriptdroid/App.java index ecc16c62..fece1814 100644 --- a/app/src/main/java/com/stardust/scriptdroid/App.java +++ b/app/src/main/java/com/stardust/scriptdroid/App.java @@ -69,8 +69,7 @@ public class App extends MultiDexApplication { return; } LeakCanary.install(this); - if (!BuildConfig.DEBUG) - Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class)); + Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class)); } private void init() { diff --git a/app/src/main/java/com/stardust/scriptdroid/tool/CrashHandler.java b/app/src/main/java/com/stardust/scriptdroid/tool/CrashHandler.java index 637e24c5..3046363e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/tool/CrashHandler.java +++ b/app/src/main/java/com/stardust/scriptdroid/tool/CrashHandler.java @@ -12,6 +12,7 @@ import android.view.WindowManager; import android.widget.Toast; import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.BuildConfig; import com.stardust.scriptdroid.R; import com.stardust.util.IntentUtil; import com.stardust.view.accessibility.AccessibilityService; @@ -25,32 +26,37 @@ public class CrashHandler implements UncaughtExceptionHandler { private static int crashCount = 0; private static long firstCrashMillis = 0; private final Class mErrorReportClass; + private UncaughtExceptionHandler mDefaultHandler; public CrashHandler(Class errorReportClass) { this.mErrorReportClass = errorReportClass; + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); } public void uncaughtException(Thread thread, Throwable ex) { + AccessibilityService service = AccessibilityService.getInstance(); + if (service != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + service.disableSelf(); + } + if(BuildConfig.DEBUG){ + mDefaultHandler.uncaughtException(thread, ex); + return; + } if (causedByBadWindowToken(ex)) { Toast.makeText(App.getApp(), R.string.text_no_floating_window_permission, Toast.LENGTH_SHORT).show(); IntentUtil.goToAppDetailSettings(App.getApp()); - return; - } - try { - Log.e(TAG, "Uncaught Exception", ex); - AccessibilityService service = AccessibilityService.getInstance(); - if (service != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - service.disableSelf(); + }else { + try { + Log.e(TAG, "Uncaught Exception", ex); + if (crashTooManyTimes()) + return; + String msg = App.getApp().getString(R.string.sorry_for_crash) + ex.toString(); + startErrorReportActivity(msg, throwableToString(ex)); + System.exit(1); + } catch (Throwable throwable) { + throwable.printStackTrace(); } - if (crashTooManyTimes()) - return; - String msg = App.getApp().getString(R.string.sorry_for_crash) + ex.toString(); - startErrorReportActivity(msg, throwableToString(ex)); - System.exit(0); - } catch (Throwable throwable) { - throwable.printStackTrace(); } - } private static boolean causedByBadWindowToken(Throwable e) { diff --git a/autojs/src/main/assets/init.js b/autojs/src/main/assets/init.js index e86b6e00..8fb3dcff 100644 --- a/autojs/src/main/assets/init.js +++ b/autojs/src/main/assets/init.js @@ -10,10 +10,6 @@ var importClass = function(pack){ } } -var loadJar = function(path){ - __runtime__.loadJar(path); -} - __runtime__.bridges.setBridges({ call: function(func, target, args){ var arr = []; @@ -59,7 +55,24 @@ var __asGlobal__ = function(obj, functions){ } } -require("__general__")(__runtime__, this); +var __exitIfError__ = function(action, defReturnValue){ + try{ + return action(); + }catch(err){ + log(err.toString()); + if(err instanceof java.lang.Throwable){ + exit(err); + }else if(err instanceof Error){ + exit(new org.mozilla.javascript.EvaluatorException(err.name + ": " + err.message, err.fileName, err.lineNumber)); + //new java.lang.RuntimeException(err.name + ": " + err.message + "\n" + err.stack)); + }else{ + exit(); + } + return defReturnValue; + } +}; + +require("__globals__")(__runtime__, this); (function(scope){ diff --git a/autojs/src/main/assets/modules/__general__.js b/autojs/src/main/assets/modules/__globals__.js similarity index 96% rename from autojs/src/main/assets/modules/__general__.js rename to autojs/src/main/assets/modules/__globals__.js index 0251b975..5e17e93f 100644 --- a/autojs/src/main/assets/modules/__general__.js +++ b/autojs/src/main/assets/modules/__globals__.js @@ -23,9 +23,8 @@ module.exports = function(__runtime__, scope){ scope.isRunning = scope.notStopped; - scope.exit = function(){ - __runtime__.exit(); - } + scope.exit = __runtime__.exit.bind(__runtime__); + scope.stop = scope.exit; diff --git a/autojs/src/main/assets/modules/__ui__.js b/autojs/src/main/assets/modules/__ui__.js index 70cbe9b6..287e0e48 100644 --- a/autojs/src/main/assets/modules/__ui__.js +++ b/autojs/src/main/assets/modules/__ui__.js @@ -15,29 +15,47 @@ module.exports = function(__runtime__, scope){ }); } - ui.id = function(id){ + ui.findById = function(id){ if(!ui.view) return null; - var v = ui.findViewByStringId(ui.view.getChildAt(0), id); + var v = ui.findByStringId(ui.view.getChildAt(0), id); if(v){ v = decorate(v); } return v; } + ui.isUiThread = function(){ + importClass(android.os.Looper); + return Looper.myLooper() == Looper.getMainLooper(); + } + ui.run = function(action){ - __runtime__.uiHandler.post(action); - } - - ui.nonUi = function(action){ - if(!ui.__executor__){ - ui.__executor__ = java.util.concurrent.Executors.newSingleThreadExecutor(); + if(ui.isUiThread()){ + return action(); } - ui.__executor__.submit(action); + var err = null; + var result; + var disposable = scope.threads.disposable(); + __runtime__.uiHandler.post(function(){ + try{ + result = action(); + disposable.setAndNotify(true); + }catch(e){ + err = e; + disposable.setAndNotify(true); + } + }); + disposable.blockedGet(); + if(err){ + throw err; + } + return result; } - ui.postDelay = function(action, delay){ - __runtime__.getUiHandler().postDelay(action, delay); + ui.post = function(action, delay){ + delay = delay || 0; + __runtime__.getUiHandler().postDelay(wrapUiAction(action), delay); } ui.statusBarColor = function(color){ @@ -57,33 +75,25 @@ module.exports = function(__runtime__, scope){ }); } - ui.findViewByStringId = function(view, id){ + ui.findByStringId = function(view, id){ return com.stardust.autojs.core.ui.JsViewHelper.findViewByStringId(view, id); } function decorate(view){ var view = Object.create(view); view._id = function(id){ - return ui.findViewByStringId(view, id); + return ui.findByStringId(view, id); } view.click = function(listener){ if(listener){ - view.setOnClickListener(new android.view.View.OnClickListener(listener)); + view.setOnClickListener(new android.view.View.OnClickListener(wrapUiAction(listener))); }else{ view.performClick(); } } view.longClick = function(listener){ if(listener){ - view.setOnLongClickListener(new android.view.View.OnLongClickListener(function(view){ - try{ - var r = listener(view); - return !!r; - }catch(e){ - console.error(e.getMessage()); - return false; - } - })); + view.setOnLongClickListener(wrapUiAction(listener, false)); }else{ view.performLongClick(); } @@ -93,6 +103,15 @@ module.exports = function(__runtime__, scope){ ui.__decorate__ = decorate; + function wrapUiAction(action, defReturnValue){ + if(typeof(activity) != 'undefined'){ + return function(){return action();}; + } + return function(){ + return __exitIfError__(action, defReturnValue); + } + } + var proxy = __runtime__.ui; proxy.__proxy__ = { set: function(name, value){ @@ -104,7 +123,7 @@ module.exports = function(__runtime__, scope){ if(cacheView){ return cacheView; } - cacheView = ui.id(name); + cacheView = ui.findById(name); if(cacheView){ ui.__view_cache__[name] = cacheView; return cacheView; diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/util/Drawables.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/util/Drawables.java index e9f9c819..6c45a79d 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/util/Drawables.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/util/Drawables.java @@ -110,7 +110,7 @@ public class Drawables { } else if(value.startsWith("data:")) { loadDataInto(view, value); }else { - view.setImageDrawable(com.stardust.autojs.core.ui.inflater.util.Drawables.parse(view, value)); + view.setImageDrawable(Drawables.parse(view, value)); } } diff --git a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java index e8280977..eddfa6cf 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java @@ -4,9 +4,7 @@ import android.os.Looper; import android.util.Log; import com.stardust.autojs.BuildConfig; -import com.stardust.autojs.execution.ScriptExecutionListener; import com.stardust.autojs.rhino.AndroidContextFactory; -import com.stardust.autojs.rhino.RhinoAndroidHelper; import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.autojs.script.JavaScriptSource; import com.stardust.autojs.script.StringScriptSource; @@ -16,8 +14,6 @@ import com.stardust.pio.UncheckedIOException; import org.mozilla.javascript.Callable; import org.mozilla.javascript.Context; -import org.mozilla.javascript.ContextFactory; -import org.mozilla.javascript.ErrorReporter; import org.mozilla.javascript.ImporterTopLevel; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; @@ -48,7 +44,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine { private Scriptable mScriptable; private Thread mThread; private android.content.Context mAndroidContext; - private Thread.UncaughtExceptionHandler mUiThreadExceptionHandler; + private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler; public RhinoJavaScriptEngine(android.content.Context context) { mAndroidContext = context; @@ -165,8 +161,12 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine { context.setWrapFactory(new WrapFactory()); } - public void setUiThreadExceptionHandler(Thread.UncaughtExceptionHandler uiThreadExceptionHandler) { - mUiThreadExceptionHandler = uiThreadExceptionHandler; + public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler uiThreadExceptionHandler) { + mUncaughtExceptionHandler = uiThreadExceptionHandler; + } + + public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { + return mUncaughtExceptionHandler; } private class WrapFactory extends org.mozilla.javascript.WrapFactory { @@ -212,7 +212,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine { try { return super.doTopCall(callable, cx, scope, thisObj, args); } catch (Exception e) { - mUiThreadExceptionHandler.uncaughtException(Thread.currentThread(), e); + mUncaughtExceptionHandler.uncaughtException(Thread.currentThread(), e); return null; } } diff --git a/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java b/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java index d9cacf31..4e643022 100644 --- a/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java +++ b/autojs/src/main/java/com/stardust/autojs/execution/LoopedBasedJavaScriptExecution.java @@ -23,7 +23,7 @@ public class LoopedBasedJavaScriptExecution extends RunnableScriptExecution { long delay = getConfig().delay; sleep(delay); final LoopBasedJavaScriptEngine javaScriptEngine = (LoopBasedJavaScriptEngine) engine; - javaScriptEngine.setUiThreadExceptionHandler((t, e) -> { + javaScriptEngine.setUncaughtExceptionHandler((t, e) -> { javaScriptEngine.forceStop(); getListener().onException(this, (Exception) e); }); diff --git a/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java b/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java index a0caafc6..da45ea72 100644 --- a/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java +++ b/autojs/src/main/java/com/stardust/autojs/execution/ScriptExecuteActivity.java @@ -49,7 +49,7 @@ public class ScriptExecuteActivity extends AppCompatActivity implements Thread.U mScriptSource = mScriptExecution.getSource(); mScriptEngine = mScriptExecution.getEngine(); mExecutionListener = mScriptExecution.getListener(); - ((RhinoJavaScriptEngine) mScriptEngine).setUiThreadExceptionHandler((t, e) -> onException((Exception) e)); + ((RhinoJavaScriptEngine) mScriptEngine).setUncaughtExceptionHandler((t, e) -> onException((Exception) e)); runScript(); } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java index ec4ea76c..ce0a6f03 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptRuntime.java @@ -9,6 +9,7 @@ import com.stardust.autojs.ScriptEngineService; import com.stardust.autojs.annotation.ScriptVariable; import com.stardust.autojs.core.accessibility.AccessibilityBridge; import com.stardust.autojs.core.image.Colors; +import com.stardust.autojs.engine.RhinoJavaScriptEngine; import com.stardust.autojs.engine.ScriptEngine; import com.stardust.autojs.rhino.AndroidClassLoader; import com.stardust.autojs.runtime.api.AbstractShell; @@ -35,6 +36,7 @@ import com.stardust.lang.ThreadCompat; import com.stardust.pio.UncheckedIOException; import com.stardust.util.ClipboardUtil; import com.stardust.autojs.core.util.ProcessShell; +import com.stardust.util.Objects; import com.stardust.util.ScreenMetrics; import com.stardust.util.SdkVersionUtil; import com.stardust.util.Supplier; @@ -42,6 +44,7 @@ import com.stardust.util.UiHandler; import com.stardust.view.accessibility.AccessibilityInfoProvider; import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.RhinoException; import java.io.File; import java.io.IOException; @@ -305,6 +308,25 @@ public class ScriptRuntime { } } + public void exit(Object obj) throws Throwable { + mThread.interrupt(); + if (!(obj instanceof Throwable)) { + console.error(obj); + return; + } + Throwable e = (Exception) obj; + if (Looper.myLooper() != Looper.getMainLooper()) { + throw e; + } else { + Thread.UncaughtExceptionHandler handler = ((RhinoJavaScriptEngine) engines.myEngine()).getUncaughtExceptionHandler(); + if (handler != null) { + handler.uncaughtException(Thread.currentThread(), e); + } else { + console.error(e); + } + } + } + @Deprecated public void stop() { exit(); diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java index 0c54ee89..25d50589 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java @@ -20,6 +20,7 @@ import com.stardust.util.ViewUtil; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; /** * Created by Stardust on 2017/12/5. @@ -30,7 +31,7 @@ public class Floaty { private JsLayoutInflater mJsLayoutInflater; private Context mContext; private UiHandler mUiHandler; - private Set mWindows = new HashSet<>(); + private Set mWindows = new CopyOnWriteArraySet<>(); private ScriptRuntime mRuntime; public Floaty(UiHandler uiHandler, UI ui, ScriptRuntime runtime) {