fix: app crash when longClick throws exception

This commit is contained in:
hyb1996
2018-01-04 21:13:12 +08:00
parent 2d287f720c
commit a51b9c24ed
11 changed files with 120 additions and 61 deletions

View File

@@ -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() {

View File

@@ -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) {

View File

@@ -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){

View File

@@ -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;

View File

@@ -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;

View File

@@ -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));
}
}

View File

@@ -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;
}
}

View File

@@ -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);
});

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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) {