fix: app crash when longClick throws exception
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<JsFloatyWindow> mWindows = new HashSet<>();
|
||||
private Set<JsFloatyWindow> mWindows = new CopyOnWriteArraySet<>();
|
||||
private ScriptRuntime mRuntime;
|
||||
|
||||
public Floaty(UiHandler uiHandler, UI ui, ScriptRuntime runtime) {
|
||||
|
||||
Reference in New Issue
Block a user