fix: piped writer causes anr

This commit is contained in:
hyb1996
2018-10-13 00:17:39 +08:00
parent 4dc37bc4ff
commit 4c482428dd
18 changed files with 232 additions and 111 deletions

View File

@@ -0,0 +1,41 @@
package com.stardust.autojs;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
/**
* Created by Stardust on 2017/12/8.
*/
public class Config {
private static Config sInstance;
private SharedPreferences mSharedPreferences;
private final Context mContext;
public Config(Context context) {
mContext = context;
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}
public static void setInstance(Config instance) {
if (sInstance != null)
throw new IllegalStateException();
sInstance = instance;
}
public static Config getInstance() {
return sInstance;
}
public boolean isPrintJavaStackTraceEnabled() {
return mSharedPreferences.getBoolean(getString(R.string.key_print_java_stack_trace), false);
}
private String getString(int resId) {
return mContext.getString(resId);
}
}

View File

@@ -1,32 +0,0 @@
package com.stardust.autojs;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
/**
* Created by Stardust on 2017/12/8.
*/
public class Pref {
private static Pref sInstance;
private SharedPreferences mSharedPreferences;
public Pref(Context context) {
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}
public static void setInstance(Pref instance) {
if (sInstance != null)
throw new IllegalStateException();
sInstance = instance;
}
public static Pref getInstance() {
return sInstance;
}
}

View File

@@ -1,7 +1,6 @@
package com.stardust.autojs;
import android.content.Context;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import com.stardust.autojs.engine.JavaScriptEngine;
@@ -21,22 +20,19 @@ import com.stardust.autojs.runtime.api.Console;
import com.stardust.autojs.script.JavaScriptSource;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.lang.ThreadCompat;
import com.stardust.util.TextUtils;
import com.stardust.util.UiHandler;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.ScriptStackElement;
import org.mozilla.javascript.WrappedException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -77,7 +73,7 @@ public class ScriptEngineService {
if (!causedByInterrupted(e)) {
if (execution.getEngine() instanceof JavaScriptEngine) {
((JavaScriptEngine) execution.getEngine()).getRuntime()
.console.error(getScriptTrace(e));
.console.error(e);
}
EVENT_BUS.post(new ScriptExecutionEvent(ScriptExecutionEvent.ON_EXCEPTION, e.getMessage()));
}
@@ -282,33 +278,4 @@ public class ScriptEngineService {
}
}
public static String getScriptTrace(Exception e) {
StringBuilder scriptTrace = new StringBuilder();
if (e instanceof RhinoException) {
RhinoException rhinoException = (RhinoException) e;
scriptTrace.append(rhinoException.details()).append("\n");
for (ScriptStackElement element : rhinoException.getScriptStack()) {
element.renderV8Style(scriptTrace);
scriptTrace.append("\n");
}
scriptTrace.append("- - - - - - - - - - -\n");
}
try {
PipedReader reader = new PipedReader(8192);
PrintWriter writer = new PrintWriter(new PipedWriter(reader));
e.printStackTrace(writer);
writer.close();
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
//scriptTrace.append(TextUtils.toEmptyIfNull(e.getMessage()));
while ((line = bufferedReader.readLine()) != null) {
scriptTrace.append("\n").append(line);
}
return scriptTrace.toString();
} catch (IOException e1) {
e1.printStackTrace();
return e.getMessage();
}
}
}

View File

@@ -3,11 +3,13 @@ package com.stardust.autojs.core.console;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.WindowManager;
import com.stardust.autojs.R;
import com.stardust.autojs.annotation.ScriptInterface;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.runtime.api.AbstractConsole;
import com.stardust.autojs.runtime.api.Console;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
@@ -118,11 +120,12 @@ public class StardustConsole extends AbstractConsole {
return mLogs;
}
public void printStackTrace(Throwable t) {
StringWriter out = new StringWriter();
PrintWriter printWriter = new PrintWriter(out);
t.printStackTrace(printWriter);
println(android.util.Log.ERROR, t.toString());
public void printAllStackTrace(Throwable t) {
println(android.util.Log.ERROR, ScriptRuntime.getStackTrace(t, true));
}
public String getStackTrace(Throwable t) {
return ScriptRuntime.getStackTrace(t, false);
}
@Override
@@ -271,4 +274,20 @@ public class StardustConsole extends AbstractConsole {
public void setTitle(CharSequence title) {
mConsoleFloaty.setTitle(title);
}
@Override
public void error(@Nullable Object data, Object... options) {
if (data instanceof Throwable) {
data = getStackTrace((Throwable) data);
}
if (options != null && options.length > 0) {
for (int i = 0; i < options.length; i++) {
Object option = options[i];
if (option instanceof Throwable) {
options[i] = getStackTrace((Throwable) option);
}
}
}
super.error(data, options);
}
}

View File

@@ -49,7 +49,7 @@ public class TimerThread extends ThreadCompat {
Looper.loop();
} catch (Exception e) {
if (!ScriptInterruptedException.causedByInterrupted(e)) {
mRuntime.console.error(Thread.currentThread().toString() + ": " + ScriptEngineService.getScriptTrace(e));
mRuntime.console.error(Thread.currentThread().toString() + ": ", e);
}
} finally {
onExit();

View File

@@ -0,0 +1,73 @@
package com.stardust.autojs.core.ui;
import android.view.View;
import com.stardust.autojs.R;
import com.stardust.autojs.core.ui.attribute.ViewAttributes;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.nativeview.NativeView;
import com.stardust.autojs.runtime.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
public class ViewExtras {
private NativeView mNativeView;
private ViewAttributes mViewAttributes;
public static ViewExtras get(View view) {
ViewExtras extras;
Object tag = view.getTag(R.id.view_tag_view_extras);
if (tag instanceof ViewExtras) {
extras = (ViewExtras) tag;
} else {
extras = new ViewExtras();
view.setTag(R.id.view_tag_view_extras, extras);
}
return extras;
}
public static ViewAttributes getViewAttributes(View view, ResourceParser parser) {
ViewExtras extras = get(view);
ViewAttributes attributes = extras.getViewAttributes();
if (attributes == null) {
attributes = new ViewAttributes(parser, view);
extras.setViewAttributes(attributes);
}
return attributes;
}
public static NativeView getNativeView(Scriptable scope, View view, Class<?> staticType, ScriptRuntime runtime) {
ViewExtras extras = get(view);
NativeView nativeView = extras.getNativeView();
if (nativeView == null) {
nativeView = new NativeView(scope, view, staticType, runtime);
extras.setNativeView(nativeView);
}
return nativeView;
}
public static NativeView getNativeView(View view) {
ViewExtras extras = get(view);
return extras.getNativeView();
}
public final NativeView getNativeView() {
return mNativeView;
}
public final ViewAttributes getViewAttributes() {
return mViewAttributes;
}
public final void setNativeView(NativeView nativeView) {
mNativeView = nativeView;
}
public final void setViewAttributes(ViewAttributes viewAttributes) {
mViewAttributes = viewAttributes;
}
}

View File

@@ -112,6 +112,7 @@ public class ViewAttributes {
init();
}
public boolean contains(String name) {
return mAttributes.containsKey(name);
}
@@ -264,7 +265,7 @@ public class ViewAttributes {
case "match_parent":
return ViewGroup.LayoutParams.MATCH_PARENT;
default:
return Dimensions.parseToPixel(dim, mView.getResources().getDisplayMetrics(), (ViewGroup) mView.getParent(), true);
return Dimensions.parseToPixel(dim, mView, (ViewGroup) mView.getParent(), true);
}
}

View File

@@ -5,6 +5,7 @@ import android.graphics.PorterDuff;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
@@ -13,6 +14,8 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.stardust.autojs.core.ui.ViewExtras;
import com.stardust.autojs.core.ui.attribute.ViewAttributes;
import com.stardust.autojs.core.ui.inflater.DynamicLayoutInflater;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.inflater.ViewInflater;
@@ -37,6 +40,7 @@ import java.util.Map;
public class BaseViewInflater<V extends View> implements ViewInflater<V> {
private static final String LOG_TAG = "BaseViewInflater";
public static final ValueMapper<PorterDuff.Mode> TINT_MODES = new ValueMapper<PorterDuff.Mode>("tintMode")
.map("add", PorterDuff.Mode.ADD)
@@ -106,9 +110,19 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
return mResourceParser.getDrawables();
}
public ResourceParser getResourceParser() {
return mResourceParser;
}
@Override
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
ViewAttributes viewAttributes = ViewExtras.getViewAttributes(view, getResourceParser());
ViewAttributes.Attribute attribute = viewAttributes.get(attr);
if (attribute != null) {
attribute.set(value);
return true;
}
Log.d(LOG_TAG, "setAttr cannot use ViewAttributes: attr = " + attr);
Integer layoutRule = null;
boolean layoutTarget = false;
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
@@ -129,7 +143,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
break;
default:
layoutParams.width = Dimensions.parseToPixel(value, view.getResources().getDisplayMetrics(), parent, true);
layoutParams.width = Dimensions.parseToPixel(value, view, parent, true);
break;
}
break;
@@ -144,7 +158,7 @@ public class BaseViewInflater<V extends View> implements ViewInflater<V> {
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
break;
default:
layoutParams.height = Dimensions.parseToPixel(value, view.getResources().getDisplayMetrics(), parent, false);
layoutParams.height = Dimensions.parseToPixel(value, view, parent, false);
break;
}
break;

View File

@@ -30,12 +30,12 @@ public class Dimensions {
private static final Pattern DIMENSION_PATTERN = Pattern.compile("([+-]?[0-9.]+)([a-zA-Z]*)");
public static int parseToPixel(String dimension, DisplayMetrics metrics, ViewGroup parent, boolean horizontal) {
if (dimension.endsWith("%")) {
public static int parseToPixel(String dimension, View view, ViewGroup parent, boolean horizontal) {
if (dimension.endsWith("%") && parent != null) {
float pct = Float.parseFloat(dimension.substring(0, dimension.length() - 1)) / 100.0f;
return (int) (pct * (horizontal ? parent.getMeasuredWidth() : parent.getMeasuredHeight()));
}
return parseToIntPixel(dimension, parent.getContext());
return parseToIntPixel(dimension, view.getContext());
}
public static float parseToPixel(String dimension, View view) {
@@ -59,7 +59,7 @@ public class Dimensions {
if (!m.matches()) {
throw new InflateException("dimension cannot be resolved: " + dimension);
}
int unit = m.groupCount() == 2 ? UNITS.getOr(m.group(2), TypedValue.COMPLEX_UNIT_DIP) : TypedValue.COMPLEX_UNIT_DIP;
int unit = m.groupCount() == 2 ? UNITS.get(m.group(2), TypedValue.COMPLEX_UNIT_DIP) : TypedValue.COMPLEX_UNIT_DIP;
float value = Integer.valueOf(m.group(1));
return TypedValue.applyDimension(unit, value, context.getResources().getDisplayMetrics());
}

View File

@@ -23,7 +23,18 @@ public class ValueMapper<V> {
}
public V getOr(String key, V defValue) {
public ValueMapper<V> mapDefault(String key, V value) {
mHashMap.put(key, value);
mHashMap.put("", value);
return this;
}
public ValueMapper<V> mapDefault(V value) {
mHashMap.put("", value);
return this;
}
public V get(String key, V defValue) {
V v = mHashMap.get(key);
if (v == null) {
return defValue;

View File

@@ -4,6 +4,7 @@ import android.view.View;
import com.stardust.autojs.R;
import com.stardust.autojs.core.ui.JsViewHelper;
import com.stardust.autojs.core.ui.ViewExtras;
import com.stardust.autojs.core.ui.attribute.ViewAttributes;
import com.stardust.autojs.rhino.NativeJavaObjectWithPrototype;
@@ -42,33 +43,14 @@ public class NativeView extends NativeJavaObjectWithPrototype {
private final View mView;
private final ViewPrototype mViewPrototype;
public NativeView(Scriptable scope, View javaObject, Class<?> staticType, com.stardust.autojs.runtime.ScriptRuntime runtime) {
super(scope, javaObject, staticType);
mViewAttributes = new ViewAttributes(runtime.ui.getResourceParser(), javaObject);
mView = javaObject;
public NativeView(Scriptable scope, View view, Class<?> staticType, com.stardust.autojs.runtime.ScriptRuntime runtime) {
super(scope, view, staticType);
mViewAttributes = ViewExtras.getViewAttributes(view, runtime.ui.getResourceParser());
mView = view;
mViewPrototype = new ViewPrototype(mView, scope, runtime);
prototype = new NativeJavaObject(scope, mViewPrototype, mViewPrototype.getClass());
}
public static NativeView fromView(Scriptable scope, View view, Class<?> staticType, com.stardust.autojs.runtime.ScriptRuntime runtime) {
Object tag = view.getTag(R.id.view_tag_native_view);
if (tag instanceof NativeView) {
return (NativeView) tag;
} else {
NativeView nativeView = new NativeView(scope, view, staticType, runtime);
view.setTag(R.id.view_tag_native_view, nativeView);
return nativeView;
}
}
public static NativeView fromView(View view) {
Object tag = view.getTag(R.id.view_tag_native_view);
if (tag instanceof NativeView)
return (NativeView) tag;
else
return null;
}
@Override
public boolean has(String name, Scriptable start) {
if (mViewAttributes.contains(name)) {

View File

@@ -11,6 +11,7 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import com.stardust.autojs.R;
import com.stardust.autojs.core.ui.ViewExtras;
import com.stardust.autojs.core.ui.inflater.DynamicLayoutInflater;
import com.stardust.autojs.core.ui.nativeview.NativeView;
import com.stardust.autojs.core.ui.nativeview.ViewPrototype;
@@ -126,7 +127,7 @@ public class JsListView extends RecyclerView {
int pos = getAdapterPosition();
return mOnItemTouchListener.onItemLongClick(JsListView.this, itemView, mDataSourceAdapter.getItem(mDataSource, pos), pos);
});
NativeView nativeView = NativeView.fromView(JsListView.this);
NativeView nativeView = ViewExtras.getNativeView(JsListView.this);
if (nativeView != null) {
ViewPrototype prototype = nativeView.getViewPrototype();
prototype.emit("item_bind", itemView, new ItemHolder(this));

View File

@@ -6,6 +6,7 @@ import android.view.View;
import com.stardust.app.GlobalAppContext;
import com.stardust.autojs.BuildConfig;
import com.stardust.autojs.core.ui.ViewExtras;
import com.stardust.autojs.core.ui.nativeview.NativeView;
import com.stardust.autojs.rhino.AndroidContextFactory;
import com.stardust.autojs.rhino.RhinoAndroidHelper;
@@ -189,7 +190,7 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
@Override
public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, Object javaObject, Class<?> staticType) {
if (javaObject instanceof View) {
return NativeView.fromView(scope, (View) javaObject, staticType, getRuntime());
return ViewExtras.getNativeView(scope, (View) javaObject, staticType, getRuntime());
}
return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
}

View File

@@ -50,9 +50,15 @@ import com.stardust.util.UiHandler;
import com.stardust.view.accessibility.AccessibilityInfoProvider;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.ScriptStackElement;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -71,6 +77,7 @@ public class ScriptRuntime {
private static final String TAG = "ScriptRuntime";
public static class Builder {
private UiHandler mUiHandler;
private Console mConsole;
@@ -384,7 +391,7 @@ public class ScriptRuntime {
try {
events.emit("exit");
} catch (Exception ignored) {
console.error("exception on exit: " + ScriptEngineService.getScriptTrace(ignored));
console.error("exception on exit: ", ignored);
}
ignoresException(threads::shutDownAll);
ignoresException(events::recycle);
@@ -427,4 +434,36 @@ public class ScriptRuntime {
return mProperties.remove(key);
}
public static String getStackTrace(Throwable e, boolean printJavaStackTrace){
StringBuilder scriptTrace = new StringBuilder();
if (e instanceof RhinoException) {
RhinoException rhinoException = (RhinoException) e;
scriptTrace.append(rhinoException.details()).append("\n");
for (ScriptStackElement element : rhinoException.getScriptStack()) {
element.renderV8Style(scriptTrace);
scriptTrace.append("\n");
}
if(printJavaStackTrace){
scriptTrace.append("- - - - - - - - - - -\n");
}else {
return scriptTrace.toString();
}
}
try {
StringWriter stringWriter = new StringWriter();
PrintWriter writer = new PrintWriter(stringWriter);
e.printStackTrace(writer);
writer.close();
BufferedReader bufferedReader = new BufferedReader(new StringReader(writer.toString()));
String line;
while ((line = bufferedReader.readLine()) != null) {
scriptTrace.append("\n").append(line);
}
return scriptTrace.toString();
} catch (IOException e1) {
e1.printStackTrace();
return e.getMessage();
}
}
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="view_tag_native_view" type="id"/>
<item name="view_tag_view_extras" type="id"/>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="key_print_java_stack_trace" translatable="false">key_print_java_stack_trace</string>
</resources>