Attempt to fix selector memeory leak. Add update checker

This commit is contained in:
hyb1996
2017-04-09 14:02:57 +08:00
parent 6844eb9841
commit 0e980c2e6a
72 changed files with 1282 additions and 415 deletions

View File

@@ -1,5 +1,5 @@
if(__engine__ == "rhino"){
if(__engine_name__ == "rhino"){
__importClassOld__ = importClass;
var importClass = function(pack){
if(typeof(pack) == "string"){
@@ -167,9 +167,9 @@ var scrollDown = function(a, b, c, d){
var input = function(a, b){
if(arguments.length == 1){
return __runtime__.automator.setText(__runtime__.editable(-1), a);
return __runtime__.automator.setText(__runtime__.automator.editable(-1), a);
}else{
return __runtime__.automator.setText(__runtime__.editable(a), b);
return __runtime__.automator.setText(__runtime__.automator.editable(a), b);
}
}
@@ -246,14 +246,18 @@ var Text = function(text){
return shell("input text " + text, true).code == 1;
}
var __selector__ = __runtime__.selector();
var selector = function(){
return __runtime__.selector(__engine__);
}
var __selector__ = selector();
var __obj__ = new java.lang.Object();
for(var x in __selector__){
if(!__obj__[x] && !this[x]){
this[x] = (function(method) {
return function(){
var s = __runtime__.selector();
var s = selector();
//这里不知道怎么写。尴尬。只能写成这样。
if(arguments.length == 0){
return s[method]();
@@ -274,8 +278,16 @@ for(var x in __selector__){
}
var open = function(path, mode){
return com.stardust.pio.PFile.open(path, mode);
var open = function(path, mode, encoding, bufferSize){
if(arguments.length == 1){
return com.stardust.pio.PFile.open(path);
}else if(arguments.length == 2){
return com.stardust.pio.PFile.open(path, mode);
}else if(arguments.length == 3){
return com.stardust.pio.PFile.open(path, mode, encoding);
}else if(arguments.length == 4){
return com.stardust.pio.PFile.open(path, mode, encoding, bufferSize);
}
}
__importClassOld__(com.stardust.autojs.runtime.api.Shell);

View File

@@ -1,6 +1,7 @@
package com.stardust.autojs;
import android.content.Context;
import android.util.Log;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.JavaScriptEngineManager;
@@ -10,6 +11,7 @@ import com.stardust.autojs.runtime.api.Console;
import com.stardust.autojs.script.ScriptSource;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -20,6 +22,7 @@ import java.util.Set;
public class ScriptEngineService {
private static final String LOG_TAG = "ScriptEngineService";
private static ScriptEngineService instance;
public static ScriptEngineService getInstance() {
@@ -73,7 +76,9 @@ public class ScriptEngineService {
}
public JavaScriptEngine createScriptEngine() {
return mJavaScriptEngineManager.createEngine();
JavaScriptEngine engine = mJavaScriptEngineManager.createEngine();
Log.i(LOG_TAG, Arrays.toString(Thread.currentThread().getStackTrace()));
return engine;
}
public void registerEngineLifecycleCallback(JavaScriptEngineManager.EngineLifecycleCallback engineLifecycleCallback) {

View File

@@ -40,6 +40,7 @@ public class ScriptExecutionTask implements Serializable {
runtime.ensureAccessibilityServiceEnabled();
}
mExecutionListener.onStart(engine, mScriptSource);
engine.setTag("script", mScriptSource);
mExecutionListener.onSuccess(engine, mScriptSource, engine.execute(mScriptSource));
} catch (Exception e) {
mExecutionListener.onException(engine, mScriptSource, e);

View File

@@ -21,12 +21,14 @@ public interface JavaScriptEngine {
Object execute(ScriptSource scriptSource);
ScriptSource getExecutedScript();
void forceStop();
void destroy();
void setTag(String key, Object value);
Object getTag(String key);
/**
* @hide
*/

View File

@@ -44,13 +44,17 @@ public abstract class JavaScriptEngineManager {
JavaScriptEngine engine = createEngineInner();
putProperties(engine);
engine.init();
addEngine(engine);
return engine;
}
private void addEngine(JavaScriptEngine engine) {
synchronized (mEngines) {
mEngines.add(engine);
if(mEngineLifecycleCallback != null){
if (mEngineLifecycleCallback != null) {
mEngineLifecycleCallback.onEngineCreate(engine);
}
}
return engine;
}
public void put(String varName, Object value) {
@@ -82,7 +86,7 @@ public abstract class JavaScriptEngineManager {
void removeEngine(JavaScriptEngine engine) {
synchronized (mEngines) {
mEngines.remove(engine);
if(mEngineLifecycleCallback != null){
if (mEngineLifecycleCallback != null) {
mEngineLifecycleCallback.onEngineRemove(engine);
}
}

View File

@@ -1,9 +1,13 @@
package com.stardust.autojs.engine;
import android.util.Log;
import com.stardust.autojs.rhino_android.AndroidContextFactory;
import com.stardust.autojs.rhino_android.RhinoAndroidHelper;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.runtime.ScriptStopException;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
@@ -12,6 +16,12 @@ import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**
* Created by Stardust on 2017/4/2.
@@ -19,17 +29,20 @@ import java.io.File;
public class RhinoJavaScriptEngine implements JavaScriptEngine {
private static final String LOG_TAG = "RhinoJavaScriptEngine";
private Context mContext;
private Scriptable mScriptable;
private Thread mThread;
private RhinoJavaScriptEngineManager mEngineManager;
private ScriptSource mScriptSource;
private Map<String, Object> mTags = new Hashtable<>();
public RhinoJavaScriptEngine(RhinoJavaScriptEngineManager engineManager) {
mEngineManager = engineManager;
mThread = Thread.currentThread();
mContext = createContext();
mScriptable = createScope(mContext);
setTag("create-traces", Arrays.toString(Thread.currentThread().getStackTrace()));
}
@Override
@@ -39,15 +52,11 @@ public class RhinoJavaScriptEngine implements JavaScriptEngine {
@Override
public Object execute(ScriptSource source) {
mScriptSource = source;
setTag("execute-traces", Arrays.toString(Thread.currentThread().getStackTrace()));
setTag("execute-source", source);
return mContext.evaluateString(mScriptable, source.getScript(), "<script>", 1, null);
}
@Override
public ScriptSource getExecutedScript() {
return mScriptSource;
}
@Override
public void forceStop() {
mThread.interrupt();
@@ -60,12 +69,37 @@ public class RhinoJavaScriptEngine implements JavaScriptEngine {
@Override
public void destroy() {
Context.exit();
// TODO: 2017/4/6 XXX :在这里回收内存池并不好
final AccessibilityNodeInfoAllocator allocator = (AccessibilityNodeInfoAllocator) getTag("allocator");
if (allocator != null) {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
//allocator.recycleAll();
}
}, 1000);
}
mEngineManager.removeEngine(this);
}
@Override
public synchronized void setTag(String key, Object value) {
mTags.put(key, value);
}
@Override
public synchronized Object getTag(String key) {
Object tag = mTags.get(key);
if (tag == null && key.equals("script")) {
Log.i(LOG_TAG, mTags.entrySet().toString());
}
return mTags.get(key);
}
@Override
public void init() {
ScriptableObject.putProperty(mScriptable, "__engine__", "rhino");
ScriptableObject.putProperty(mScriptable, "__engine_name__", "rhino");
ScriptableObject.putProperty(mScriptable, "__engine__", this);
mContext.evaluateString(mScriptable, mEngineManager.getInitScript().getScript(), "<init>", 1, null);
}

View File

@@ -31,6 +31,7 @@ public class RhinoJavaScriptEngineManager extends JavaScriptEngineManager {
private String mRequirePath = "";
public RhinoJavaScriptEngineManager(android.content.Context context, ScriptRuntime runtime) {
super(context);
put("__runtime__", runtime);
@@ -65,7 +66,9 @@ public class RhinoJavaScriptEngineManager extends JavaScriptEngineManager {
private String[] getGlobalFunctionsInner() {
JavaScriptEngine engine = createEngine();
Scriptable scriptable = (Scriptable) engine.execute(new StringScriptSource("this"));
ScriptSource source = new StringScriptSource("this", "this");
engine.setTag("script", source);
Scriptable scriptable = (Scriptable) engine.execute(source);
Object[] ids = scriptable.getIds();
String[] functions = new String[ids.length];
for (int i = 0; i < ids.length; i++) {

View File

@@ -46,6 +46,7 @@ public class ScriptExecuteActivity extends Activity {
private void runScript() {
mJavaScriptEngine.put("activity", this);
try {
mJavaScriptEngine.setTag("script", mScriptSource);
mResult = mJavaScriptEngine.execute(mScriptSource);
} catch (Exception e) {
mExecutionListener.onException(mJavaScriptEngine, mScriptSource, e);

View File

@@ -6,6 +6,7 @@ import android.os.Handler;
import android.widget.Toast;
import com.stardust.autojs.R;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.rhino_android.AndroidClassLoader;
import com.stardust.autojs.runtime.simple_action.SimpleActionAutomator;
import com.stardust.autojs.runtime.api.AppUtils;
@@ -16,6 +17,7 @@ import com.stardust.util.ClipboardUtil;
import com.stardust.util.SdkVersionUtil;
import com.stardust.util.Shell;
import com.stardust.view.accessibility.AccessibilityInfoProvider;
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
import org.mozilla.javascript.ContextFactory;
@@ -92,8 +94,13 @@ public class ScriptRuntime {
}
@JavascriptInterface
public UiSelector selector() {
return new UiSelector(mAccessibilityBridge);
public UiSelector selector(JavaScriptEngine engine) {
AccessibilityNodeInfoAllocator allocator = (AccessibilityNodeInfoAllocator) engine.getTag("allocator");
if(allocator == null){
allocator = new AccessibilityNodeInfoAllocator();
engine.setTag("allocator", allocator);
}
return new UiSelector(mAccessibilityBridge, allocator);
}
@JavascriptInterface

View File

@@ -7,12 +7,14 @@ import android.view.accessibility.AccessibilityNodeInfo;
import com.stardust.autojs.runtime.AccessibilityBridge;
import com.stardust.autojs.runtime.JavascriptInterface;
import com.stardust.autojs.runtime.ScriptStopException;
import com.stardust.automator.AccessibilityEventCommandHost;
import com.stardust.automator.ActionArgument;
import com.stardust.automator.UiGlobalSelector;
import com.stardust.automator.UiObject;
import com.stardust.automator.UiObjectCollection;
import com.stardust.automator.filter.DfsFilter;
import com.stardust.util.DeveloperUtils;
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
@@ -53,6 +55,7 @@ import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.
public class UiSelector extends UiGlobalSelector {
@Deprecated
private class FindCommand extends AccessibilityEventCommandHost.AbstractCommand {
UiObjectCollection result;
@@ -70,20 +73,28 @@ public class UiSelector extends UiGlobalSelector {
private static final String TAG = "UiSelector";
private AccessibilityBridge mAccessibilityBridge;
private AccessibilityNodeInfoAllocator mAllocator = AccessibilityNodeInfoAllocator.getGlobal();
public UiSelector(AccessibilityBridge accessibilityBridge) {
mAccessibilityBridge = accessibilityBridge;
}
public UiSelector(AccessibilityBridge accessibilityBridge, AccessibilityNodeInfoAllocator allocator) {
mAccessibilityBridge = accessibilityBridge;
mAllocator = allocator;
}
@JavascriptInterface
public UiObjectCollection find() {
ensureAccessibilityServiceEnabled();
if (isRunningPackageSelf()) {
return null;
}
AccessibilityService service = mAccessibilityBridge.getService();
if (service != null) {
AccessibilityNodeInfo root = service.getRootInActiveWindow();
if (root != null) {
return findOf(root);
return findOf(mAllocator, root);
}
}
return null;
@@ -93,12 +104,19 @@ public class UiSelector extends UiGlobalSelector {
mAccessibilityBridge.ensureServiceEnabled();
}
private boolean isRunningPackageSelf() {
return DeveloperUtils.isRunningPackageSelf(mAccessibilityBridge.getInfoProvider().getLatestPackage());
}
@JavascriptInterface
@NonNull
public UiObjectCollection untilFind() {
UiObjectCollection uiObjectCollection;
do {
if (Thread.currentThread().isInterrupted()) {
throw new ScriptStopException(new InterruptedException());
}
uiObjectCollection = find();
} while (uiObjectCollection == null || uiObjectCollection.size() == 0);
return uiObjectCollection;

View File

@@ -15,6 +15,8 @@ import com.stardust.automator.AccessibilityEventCommandHost;
import com.stardust.automator.simple_action.SimpleAction;
import com.stardust.automator.simple_action.ActionFactory;
import com.stardust.automator.simple_action.ActionTarget;
import com.stardust.util.DeveloperUtils;
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
/**
* Created by Stardust on 2017/4/2.
@@ -180,16 +182,26 @@ public class SimpleActionAutomator {
}
@SuppressWarnings("unchecked")
private <T> T performAction(SimpleAction simpleAction) {
private boolean performAction(SimpleAction simpleAction) {
ensureAccessibilityServiceEnabled();
AccessibilityService service = mAccessibilityBridge.getService();
if (service != null) {
AccessibilityNodeInfo root = service.getRootInActiveWindow();
Log.i("Automator", "performAction: " + simpleAction + " root = " + root);
if (root != null) {
simpleAction.setResult(simpleAction.perform(root));
}
if (isRunningPackageSelf()) {
return false;
}
return (T) simpleAction.getResult();
AccessibilityService service = mAccessibilityBridge.getService();
if (service == null)
return false;
AccessibilityNodeInfo root = service.getRootInActiveWindow();
if (root == null)
return false;
AccessibilityNodeInfoAllocator allocator = new AccessibilityNodeInfoAllocator();
simpleAction.setAllocator(allocator);
Log.i("Automator", "performAction: " + simpleAction + " root = " + root);
boolean result = simpleAction.perform(root);
allocator.recycleAll();
return result;
}
private boolean isRunningPackageSelf() {
return DeveloperUtils.isRunningPackageSelf(mAccessibilityBridge.getInfoProvider().getLatestPackage());
}
}