diff --git a/autojs/src/main/java/com/stardust/autojs/AutoJs.java b/autojs/src/main/java/com/stardust/autojs/AutoJs.java index d65b7780..7897e98c 100644 --- a/autojs/src/main/java/com/stardust/autojs/AutoJs.java +++ b/autojs/src/main/java/com/stardust/autojs/AutoJs.java @@ -21,7 +21,7 @@ import com.stardust.autojs.core.util.Shell; import com.stardust.autojs.engine.LoopBasedJavaScriptEngine; import com.stardust.autojs.engine.RootAutomatorEngine; import com.stardust.autojs.engine.ScriptEngineManager; -import com.stardust.autojs.rhino.InterruptibleAndroidContextFactory; +import com.stardust.autojs.rhino.InterruptableAndroidContextFactory; import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.autojs.runtime.accessibility.AccessibilityConfig; import com.stardust.autojs.runtime.api.AppUtils; @@ -129,7 +129,7 @@ public abstract class AutoJs { } protected void initContextFactory() { - ContextFactory.initGlobal(new InterruptibleAndroidContextFactory(new File(mContext.getCacheDir(), "classes"))); + ContextFactory.initGlobal(new InterruptableAndroidContextFactory(new File(mContext.getCacheDir(), "classes"))); } protected ScriptRuntime createRuntime() { diff --git a/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java b/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java index db623ff6..dce8cebf 100644 --- a/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java +++ b/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java @@ -87,7 +87,7 @@ public class ScriptEngineService { }; - private static ScriptEngineService sInstance; + private static volatile ScriptEngineService sInstance; private final Context mContext; private UiHandler mUiHandler; private final Console mGlobalConsole; @@ -209,8 +209,12 @@ public class ScriptEngineService { } public static void setInstance(ScriptEngineService service) { - if (sInstance != null) { - throw new IllegalStateException(); + if (sInstance == null) { + synchronized (ScriptEngineService.class) { + if (sInstance != null) { + throw new IllegalStateException(); + } + } } sInstance = service; } diff --git a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt index 0fd0bbc1..bdc1edc0 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt +++ b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt @@ -99,10 +99,19 @@ open class RhinoJavaScriptEngine(private val mAndroidContext: android.content.Co @Synchronized override fun destroy() { - super.destroy() - Log.d(LOG_TAG, "on destroy") - sContextEngineMap.remove(context) - Context.exit() + var destroySuccess = false; + try { + super.destroy() + Log.d(LOG_TAG, "on destroy") + sContextEngineMap.remove(context) + destroySuccess = true; + } finally { + if (destroySuccess) + Log.d(LOG_TAG, "destroy execute success") + else + Log.d(LOG_TAG, "destroy execute failed") + Context.exit() + } } override fun init() { @@ -151,6 +160,10 @@ open class RhinoJavaScriptEngine(private val mAndroidContext: android.content.Co context.wrapFactory = WrapFactory() } + protected fun removeContext(context: Context) { + context.wrapFactory = null + } + private inner class WrapFactory : org.mozilla.javascript.WrapFactory() { override fun wrap(cx: Context, scope: Scriptable, obj: Any?, staticType: Class<*>?): Any? { diff --git a/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java b/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java index 4ae37ef7..4bf4dbf0 100644 --- a/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java +++ b/autojs/src/main/java/com/stardust/autojs/rhino/AndroidClassLoader.java @@ -1,5 +1,7 @@ package com.stardust.autojs.rhino; +import java.util.WeakHashMap; + import android.util.Log; import com.android.dx.command.dexer.Main; @@ -17,14 +19,11 @@ import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; -import java.util.TreeMap; import dalvik.system.DexClassLoader; @@ -41,6 +40,8 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa private final File mCacheDir; private final File mLibsDir; + private final WeakHashMap weakDexFileMap = new WeakHashMap<>(); + /** * Create a new instance with the given parent classloader and cache dierctory * @@ -168,7 +169,10 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa Main.run(arguments); DexClassLoader loader = loadDex(dexFile); if (isTmpDex) { - dexFile.delete(); + Log.d(LOG_TAG, "delete tmpFile on finalize:" + dexFile.getName()); + // 当弱引用失去引用时 删除File对象 + weakDexFileMap.put(new DeleteOnFinalizeFile(dexFile), dexFile.getName()); + Log.d(LOG_TAG, "current weakMap size:" + weakDexFileMap.size()); } return loader; } @@ -196,15 +200,26 @@ public class AndroidClassLoader extends ClassLoader implements GeneratedClassLoa throws ClassNotFoundException { Class loadedClass = findLoadedClass(name); if (loadedClass == null) { - ListIterator reverseIterator = new ArrayList<>(mDexClassLoaders.values()).listIterator(mDexClassLoaders.size()); - while (reverseIterator.hasPrevious()) { - loadedClass = reverseIterator.previous().loadClass(name); - if (loadedClass != null) { - break; + if (parent != null) { + try { + loadedClass = parent.loadClass(name); + } catch (Exception e) { + // do nothing } } if (loadedClass == null) { - loadedClass = parent.loadClass(name); + ListIterator reverseIterator = new ArrayList<>(mDexClassLoaders.values()).listIterator(mDexClassLoaders.size()); + while (reverseIterator.hasPrevious()) { + DexClassLoader classLoader = reverseIterator.previous(); +// Log.d(LOG_TAG, "try to load class: " + name + " class loader info: " + classLoader.toString()); + loadedClass = classLoader.loadClass(name); + if (loadedClass != null) { + break; + } + } + } + if (loadedClass == null) { + loadedClass = findClass(name); } } return loadedClass; diff --git a/autojs/src/main/java/com/stardust/autojs/rhino/DeleteOnFinalizeFile.java b/autojs/src/main/java/com/stardust/autojs/rhino/DeleteOnFinalizeFile.java new file mode 100644 index 00000000..e0069e3e --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/rhino/DeleteOnFinalizeFile.java @@ -0,0 +1,26 @@ +package com.stardust.autojs.rhino; + +import android.util.Log; + +import java.io.File; + +public class DeleteOnFinalizeFile { + + private File fileObject; + + private String LOG_TAG = "DeleteOnFinalizeFile"; + + public DeleteOnFinalizeFile(File file) { + fileObject = file; + } + + @Override + protected void finalize() throws Throwable { + if (fileObject != null) { + Log.d(LOG_TAG, "finalize delete file" + fileObject.getName()); + if (fileObject.exists()) + fileObject.delete(); + } + super.finalize(); + } +} diff --git a/autojs/src/main/java/com/stardust/autojs/rhino/InterruptibleAndroidContextFactory.java b/autojs/src/main/java/com/stardust/autojs/rhino/InterruptableAndroidContextFactory.java similarity index 92% rename from autojs/src/main/java/com/stardust/autojs/rhino/InterruptibleAndroidContextFactory.java rename to autojs/src/main/java/com/stardust/autojs/rhino/InterruptableAndroidContextFactory.java index 07fcc61b..8a0dcd54 100644 --- a/autojs/src/main/java/com/stardust/autojs/rhino/InterruptibleAndroidContextFactory.java +++ b/autojs/src/main/java/com/stardust/autojs/rhino/InterruptableAndroidContextFactory.java @@ -10,7 +10,7 @@ import org.mozilla.javascript.Context; import java.io.File; import java.util.concurrent.atomic.AtomicInteger; -public class InterruptibleAndroidContextFactory extends AndroidContextFactory { +public class InterruptableAndroidContextFactory extends AndroidContextFactory { private AtomicInteger mContextCount = new AtomicInteger(); private static final String LOG_TAG = "ContextFactory"; @@ -20,7 +20,7 @@ public class InterruptibleAndroidContextFactory extends AndroidContextFactory { * * @param cacheDirectory the cache directory */ - public InterruptibleAndroidContextFactory(File cacheDirectory) { + public InterruptableAndroidContextFactory(File cacheDirectory) { super(cacheDirectory); }