From 65aeb754f20d9923609059b9c3730896b4b9848a Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Wed, 31 Oct 2018 14:02:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20captureScreen()=E8=BF=94?= =?UTF-8?q?=E5=9B=9Enull=E7=9A=84=E9=97=AE=E9=A2=98=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20ResourceMonitor=E7=9A=84=E9=94=99=E8=AF=AF=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/stardust/autojs/AutoJs.java | 14 +++++ .../core/image/capture/ScreenCapturer.java | 58 ++++++----------- .../com/stardust/autojs/core/opencv/Mat.java | 1 + .../stardust/autojs/runtime/api/Images.java | 2 +- .../com/stardust/util/ResourceMonitor.java | 63 ++++++++++++++----- 5 files changed, 82 insertions(+), 56 deletions(-) diff --git a/autojs/src/main/java/com/stardust/autojs/AutoJs.java b/autojs/src/main/java/com/stardust/autojs/AutoJs.java index 7aa45048..e6ea7334 100644 --- a/autojs/src/main/java/com/stardust/autojs/AutoJs.java +++ b/autojs/src/main/java/com/stardust/autojs/AutoJs.java @@ -26,6 +26,7 @@ import com.stardust.autojs.runtime.accessibility.AccessibilityConfig; import com.stardust.autojs.runtime.api.AppUtils; import com.stardust.autojs.script.AutoFileSource; import com.stardust.autojs.script.JavaScriptSource; +import com.stardust.util.ResourceMonitor; import com.stardust.util.ScreenMetrics; import com.stardust.util.UiHandler; import com.stardust.view.accessibility.AccessibilityInfoProvider; @@ -34,7 +35,9 @@ import com.stardust.view.accessibility.AccessibilityService; import com.stardust.view.accessibility.LayoutInspector; import org.mozilla.javascript.ContextFactory; +import org.mozilla.javascript.RhinoException; import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.WrappedException; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.OpenCVLoader; @@ -90,6 +93,17 @@ public abstract class AutoJs { } catch (Exception e) { e.printStackTrace(); } + ResourceMonitor.setExceptionCreator(resource -> { + Exception exception; + if (org.mozilla.javascript.Context.getCurrentContext() != null) { + exception = new WrappedException(new ResourceMonitor.UnclosedResourceException(resource)); + } else { + exception = new ResourceMonitor.UnclosedResourceException(resource); + } + exception.fillInStackTrace(); + return exception; + }); + ResourceMonitor.setUnclosedResourceDetectedHandler(detectedException -> mGlobalConsole.error(detectedException)); } public abstract void ensureAccessibilityServiceEnabled(); diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCapturer.java b/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCapturer.java index 55fc9b18..a0f5e064 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCapturer.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/capture/ScreenCapturer.java @@ -23,6 +23,8 @@ import com.stardust.autojs.runtime.exception.ScriptException; import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.util.ScreenMetrics; +import java.util.concurrent.atomic.AtomicReference; + /** * Created by Stardust on 2017/5/17. */ @@ -32,15 +34,13 @@ public class ScreenCapturer { public static final int ORIENTATION_AUTO = -1; private static final String LOG_TAG = "ScreenCapturer"; - private final Object mCachedImageLock = new Object(); private final MediaProjectionManager mProjectionManager; private ImageReader mImageReader; private MediaProjection mMediaProjection; private VirtualDisplay mVirtualDisplay; private volatile Looper mImageAcquireLooper; private volatile Image mUnderUsingImage; - private volatile Image mCachedImage; - private volatile boolean mImageAvailable = false; + private volatile AtomicReference mCachedImage = new AtomicReference<>(); private volatile Exception mException; private final int mScreenDensity; private Handler mHandler; @@ -98,7 +98,6 @@ public class ScreenCapturer { if (mVirtualDisplay != null) { mVirtualDisplay.release(); } - mImageAvailable = false; if (mMediaProjection != null) { mMediaProjection.stop(); } @@ -110,7 +109,7 @@ public class ScreenCapturer { } private void initVirtualDisplay(int width, int height, int screenDensity) { - mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2); + mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 3); mVirtualDisplay = mMediaProjection.createVirtualDisplay(LOG_TAG, width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null); @@ -134,18 +133,11 @@ public class ScreenCapturer { private void setImageListener(Handler handler) { mImageReader.setOnImageAvailableListener(reader -> { try { - if (mCachedImage != null) { - synchronized (mCachedImageLock) { - if (mCachedImage != null) { - mCachedImage.close(); - } - mCachedImage = reader.acquireLatestImage(); - mImageAvailable = true; - mCachedImageLock.notify(); - return; - } + Image oldCacheImage = mCachedImage.getAndSet(null); + if (oldCacheImage != null) { + oldCacheImage.close(); } - mCachedImage = reader.acquireLatestImage(); + mCachedImage.set(reader.acquireLatestImage()); } catch (Exception e) { mException = e; } @@ -155,34 +147,19 @@ public class ScreenCapturer { @Nullable public Image capture() { - if (!mImageAvailable) { - waitForImageAvailable(); - } if (mException != null) { Exception e = mException; mException = null; throw new ScriptException(e); } - synchronized (mCachedImageLock) { - if (mCachedImage != null) { - if (mUnderUsingImage != null) + while (true) { + Image cachedImage = mCachedImage.getAndSet(null); + if (cachedImage != null) { + if (mUnderUsingImage != null) { mUnderUsingImage.close(); - mUnderUsingImage = mCachedImage; - mCachedImage = null; - } - } - return mUnderUsingImage; - } - - private void waitForImageAvailable() { - synchronized (mCachedImageLock) { - if (mImageAvailable) { - return; - } - try { - mCachedImageLock.wait(); - } catch (InterruptedException e) { - throw new ScriptInterruptedException(); + } + mUnderUsingImage = cachedImage; + return cachedImage; } } } @@ -209,8 +186,9 @@ public class ScreenCapturer { if (mUnderUsingImage != null) { mUnderUsingImage.close(); } - if (mCachedImage != null) { - mCachedImage.close(); + Image cachedImage = mCachedImage.getAndSet(null); + if (cachedImage != null) { + cachedImage.close(); } if (mOrientationEventListener != null) { mOrientationEventListener.disable(); diff --git a/autojs/src/main/java/com/stardust/autojs/core/opencv/Mat.java b/autojs/src/main/java/com/stardust/autojs/core/opencv/Mat.java index 4c4e9c3d..7a9e74be 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/opencv/Mat.java +++ b/autojs/src/main/java/com/stardust/autojs/core/opencv/Mat.java @@ -2,6 +2,7 @@ package com.stardust.autojs.core.opencv; import com.stardust.util.ResourceMonitor; +import org.mozilla.javascript.ScriptRuntime; import org.opencv.core.Range; import org.opencv.core.Rect; import org.opencv.core.Scalar; diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java index 7fc52b4d..4f28a30c 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java @@ -101,7 +101,7 @@ public class Images { } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public ImageWrapper captureScreen() { + public synchronized ImageWrapper captureScreen() { ScriptRuntime.requiresApi(21); if (mScreenCapturer == null) { throw new SecurityException("No screen capture permission"); diff --git a/common/src/main/java/com/stardust/util/ResourceMonitor.java b/common/src/main/java/com/stardust/util/ResourceMonitor.java index 55eb133d..0e506f47 100644 --- a/common/src/main/java/com/stardust/util/ResourceMonitor.java +++ b/common/src/main/java/com/stardust/util/ResourceMonitor.java @@ -2,6 +2,7 @@ package com.stardust.util; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.util.SparseArray; import com.stardust.BuildConfig; @@ -13,22 +14,37 @@ public final class ResourceMonitor { private static final String LOG_TAG = "ResourceMonitor"; - private static final ConcurrentHashMap, SparseArray> mResources = new ConcurrentHashMap<>(); - private static Handler mHandler; - private static boolean mEnabled = false; + private static final ConcurrentHashMap, SparseArray> mResources = new ConcurrentHashMap<>(); + private static Handler sHandler; + private static boolean mEnabled = BuildConfig.DEBUG; + private static ExceptionCreator sExceptionCreator; + private static UnclosedResourceDetectedHandler sUnclosedResourceDetectedHandler; + + public static void setExceptionCreator(ExceptionCreator exceptionCreator) { + sExceptionCreator = exceptionCreator; + } + + public static void setUnclosedResourceDetectedHandler(UnclosedResourceDetectedHandler unclosedResourceDetectedHandler) { + sUnclosedResourceDetectedHandler = unclosedResourceDetectedHandler; + } public static void onOpen(ResourceMonitor.Resource resource) { if (!mEnabled) { return; } - SparseArray map = mResources.get(resource.getClass()); + SparseArray map = mResources.get(resource.getClass()); if (map == null) { map = new SparseArray<>(); mResources.put(resource.getClass(), map); } int resourceId = resource.getResourceId(); - ResourceMonitor.UnclosedResourceException exception = new ResourceMonitor.UnclosedResourceException("id = " + resourceId + ", resource = " + resource); - exception.fillInStackTrace(); + Exception exception; + if (sExceptionCreator == null) { + exception = new ResourceMonitor.UnclosedResourceException(resource); + exception.fillInStackTrace(); + } else { + exception = sExceptionCreator.create(resource); + } map.put(resourceId, exception); } @@ -46,18 +62,25 @@ public final class ResourceMonitor { if (!mEnabled) { return; } - SparseArray map = mResources.get(resource.getClass()); + SparseArray map = mResources.get(resource.getClass()); if (map != null) { int indexOfKey = map.indexOfKey(resource.getResourceId()); if (indexOfKey >= 0) { - final ResourceMonitor.UnclosedResourceException unclosedResourceException = map.valueAt(indexOfKey); + final Exception exception = map.valueAt(indexOfKey); map.removeAt(indexOfKey); - if (mHandler == null) { - mHandler = new Handler(Looper.getMainLooper()); + if (sHandler == null) { + sHandler = new Handler(Looper.getMainLooper()); } - mHandler.post(new Runnable() { + sHandler.post(new Runnable() { public final void run() { - throw new UnclosedResourceDetectedException(unclosedResourceException); + UnclosedResourceDetectedException detectedException = new UnclosedResourceDetectedException(exception); + detectedException.fillInStackTrace(); + Log.w(LOG_TAG, "UnclosedResourceDetected", detectedException); + if (sUnclosedResourceDetectedHandler != null) { + sUnclosedResourceDetectedHandler.onUnclosedResourceDetected(detectedException); + } else { + throw detectedException; + } } }); } @@ -73,14 +96,15 @@ public final class ResourceMonitor { } public static final class UnclosedResourceException extends RuntimeException { - public UnclosedResourceException(String message) { - super(message); + public UnclosedResourceException(Resource resource) { + super("id = " + resource.getResourceId() + ", resource = " + resource); } + } public static final class UnclosedResourceDetectedException extends RuntimeException { - public UnclosedResourceDetectedException(ResourceMonitor.UnclosedResourceException cause) { + public UnclosedResourceDetectedException(Throwable cause) { super(cause); } } @@ -88,4 +112,13 @@ public final class ResourceMonitor { public interface Resource { int getResourceId(); } + + public interface ExceptionCreator { + Exception create(Resource resource); + } + + public interface UnclosedResourceDetectedHandler { + + void onUnclosedResourceDetected(UnclosedResourceDetectedException detectedException); + } }