优化 captureScreen()返回null的问题
优化 ResourceMonitor的错误显示
This commit is contained in:
@@ -26,6 +26,7 @@ import com.stardust.autojs.runtime.accessibility.AccessibilityConfig;
|
|||||||
import com.stardust.autojs.runtime.api.AppUtils;
|
import com.stardust.autojs.runtime.api.AppUtils;
|
||||||
import com.stardust.autojs.script.AutoFileSource;
|
import com.stardust.autojs.script.AutoFileSource;
|
||||||
import com.stardust.autojs.script.JavaScriptSource;
|
import com.stardust.autojs.script.JavaScriptSource;
|
||||||
|
import com.stardust.util.ResourceMonitor;
|
||||||
import com.stardust.util.ScreenMetrics;
|
import com.stardust.util.ScreenMetrics;
|
||||||
import com.stardust.util.UiHandler;
|
import com.stardust.util.UiHandler;
|
||||||
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
||||||
@@ -34,7 +35,9 @@ import com.stardust.view.accessibility.AccessibilityService;
|
|||||||
import com.stardust.view.accessibility.LayoutInspector;
|
import com.stardust.view.accessibility.LayoutInspector;
|
||||||
|
|
||||||
import org.mozilla.javascript.ContextFactory;
|
import org.mozilla.javascript.ContextFactory;
|
||||||
|
import org.mozilla.javascript.RhinoException;
|
||||||
import org.mozilla.javascript.Scriptable;
|
import org.mozilla.javascript.Scriptable;
|
||||||
|
import org.mozilla.javascript.WrappedException;
|
||||||
import org.opencv.android.BaseLoaderCallback;
|
import org.opencv.android.BaseLoaderCallback;
|
||||||
import org.opencv.android.OpenCVLoader;
|
import org.opencv.android.OpenCVLoader;
|
||||||
|
|
||||||
@@ -90,6 +93,17 @@ public abstract class AutoJs {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
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();
|
public abstract void ensureAccessibilityServiceEnabled();
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import com.stardust.autojs.runtime.exception.ScriptException;
|
|||||||
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||||
import com.stardust.util.ScreenMetrics;
|
import com.stardust.util.ScreenMetrics;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/5/17.
|
* Created by Stardust on 2017/5/17.
|
||||||
*/
|
*/
|
||||||
@@ -32,15 +34,13 @@ public class ScreenCapturer {
|
|||||||
public static final int ORIENTATION_AUTO = -1;
|
public static final int ORIENTATION_AUTO = -1;
|
||||||
|
|
||||||
private static final String LOG_TAG = "ScreenCapturer";
|
private static final String LOG_TAG = "ScreenCapturer";
|
||||||
private final Object mCachedImageLock = new Object();
|
|
||||||
private final MediaProjectionManager mProjectionManager;
|
private final MediaProjectionManager mProjectionManager;
|
||||||
private ImageReader mImageReader;
|
private ImageReader mImageReader;
|
||||||
private MediaProjection mMediaProjection;
|
private MediaProjection mMediaProjection;
|
||||||
private VirtualDisplay mVirtualDisplay;
|
private VirtualDisplay mVirtualDisplay;
|
||||||
private volatile Looper mImageAcquireLooper;
|
private volatile Looper mImageAcquireLooper;
|
||||||
private volatile Image mUnderUsingImage;
|
private volatile Image mUnderUsingImage;
|
||||||
private volatile Image mCachedImage;
|
private volatile AtomicReference<Image> mCachedImage = new AtomicReference<>();
|
||||||
private volatile boolean mImageAvailable = false;
|
|
||||||
private volatile Exception mException;
|
private volatile Exception mException;
|
||||||
private final int mScreenDensity;
|
private final int mScreenDensity;
|
||||||
private Handler mHandler;
|
private Handler mHandler;
|
||||||
@@ -98,7 +98,6 @@ public class ScreenCapturer {
|
|||||||
if (mVirtualDisplay != null) {
|
if (mVirtualDisplay != null) {
|
||||||
mVirtualDisplay.release();
|
mVirtualDisplay.release();
|
||||||
}
|
}
|
||||||
mImageAvailable = false;
|
|
||||||
if (mMediaProjection != null) {
|
if (mMediaProjection != null) {
|
||||||
mMediaProjection.stop();
|
mMediaProjection.stop();
|
||||||
}
|
}
|
||||||
@@ -110,7 +109,7 @@ public class ScreenCapturer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initVirtualDisplay(int width, int height, int screenDensity) {
|
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,
|
mVirtualDisplay = mMediaProjection.createVirtualDisplay(LOG_TAG,
|
||||||
width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
width, height, screenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
|
||||||
mImageReader.getSurface(), null, null);
|
mImageReader.getSurface(), null, null);
|
||||||
@@ -134,18 +133,11 @@ public class ScreenCapturer {
|
|||||||
private void setImageListener(Handler handler) {
|
private void setImageListener(Handler handler) {
|
||||||
mImageReader.setOnImageAvailableListener(reader -> {
|
mImageReader.setOnImageAvailableListener(reader -> {
|
||||||
try {
|
try {
|
||||||
if (mCachedImage != null) {
|
Image oldCacheImage = mCachedImage.getAndSet(null);
|
||||||
synchronized (mCachedImageLock) {
|
if (oldCacheImage != null) {
|
||||||
if (mCachedImage != null) {
|
oldCacheImage.close();
|
||||||
mCachedImage.close();
|
|
||||||
}
|
}
|
||||||
mCachedImage = reader.acquireLatestImage();
|
mCachedImage.set(reader.acquireLatestImage());
|
||||||
mImageAvailable = true;
|
|
||||||
mCachedImageLock.notify();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mCachedImage = reader.acquireLatestImage();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
mException = e;
|
mException = e;
|
||||||
}
|
}
|
||||||
@@ -155,34 +147,19 @@ public class ScreenCapturer {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Image capture() {
|
public Image capture() {
|
||||||
if (!mImageAvailable) {
|
|
||||||
waitForImageAvailable();
|
|
||||||
}
|
|
||||||
if (mException != null) {
|
if (mException != null) {
|
||||||
Exception e = mException;
|
Exception e = mException;
|
||||||
mException = null;
|
mException = null;
|
||||||
throw new ScriptException(e);
|
throw new ScriptException(e);
|
||||||
}
|
}
|
||||||
synchronized (mCachedImageLock) {
|
while (true) {
|
||||||
if (mCachedImage != null) {
|
Image cachedImage = mCachedImage.getAndSet(null);
|
||||||
if (mUnderUsingImage != null)
|
if (cachedImage != null) {
|
||||||
|
if (mUnderUsingImage != null) {
|
||||||
mUnderUsingImage.close();
|
mUnderUsingImage.close();
|
||||||
mUnderUsingImage = mCachedImage;
|
|
||||||
mCachedImage = null;
|
|
||||||
}
|
}
|
||||||
}
|
mUnderUsingImage = cachedImage;
|
||||||
return mUnderUsingImage;
|
return cachedImage;
|
||||||
}
|
|
||||||
|
|
||||||
private void waitForImageAvailable() {
|
|
||||||
synchronized (mCachedImageLock) {
|
|
||||||
if (mImageAvailable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
mCachedImageLock.wait();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new ScriptInterruptedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,8 +186,9 @@ public class ScreenCapturer {
|
|||||||
if (mUnderUsingImage != null) {
|
if (mUnderUsingImage != null) {
|
||||||
mUnderUsingImage.close();
|
mUnderUsingImage.close();
|
||||||
}
|
}
|
||||||
if (mCachedImage != null) {
|
Image cachedImage = mCachedImage.getAndSet(null);
|
||||||
mCachedImage.close();
|
if (cachedImage != null) {
|
||||||
|
cachedImage.close();
|
||||||
}
|
}
|
||||||
if (mOrientationEventListener != null) {
|
if (mOrientationEventListener != null) {
|
||||||
mOrientationEventListener.disable();
|
mOrientationEventListener.disable();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.stardust.autojs.core.opencv;
|
|||||||
|
|
||||||
import com.stardust.util.ResourceMonitor;
|
import com.stardust.util.ResourceMonitor;
|
||||||
|
|
||||||
|
import org.mozilla.javascript.ScriptRuntime;
|
||||||
import org.opencv.core.Range;
|
import org.opencv.core.Range;
|
||||||
import org.opencv.core.Rect;
|
import org.opencv.core.Rect;
|
||||||
import org.opencv.core.Scalar;
|
import org.opencv.core.Scalar;
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class Images {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
public ImageWrapper captureScreen() {
|
public synchronized ImageWrapper captureScreen() {
|
||||||
ScriptRuntime.requiresApi(21);
|
ScriptRuntime.requiresApi(21);
|
||||||
if (mScreenCapturer == null) {
|
if (mScreenCapturer == null) {
|
||||||
throw new SecurityException("No screen capture permission");
|
throw new SecurityException("No screen capture permission");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.stardust.util;
|
|||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.stardust.BuildConfig;
|
import com.stardust.BuildConfig;
|
||||||
@@ -13,22 +14,37 @@ public final class ResourceMonitor {
|
|||||||
|
|
||||||
private static final String LOG_TAG = "ResourceMonitor";
|
private static final String LOG_TAG = "ResourceMonitor";
|
||||||
|
|
||||||
private static final ConcurrentHashMap<Class<?>, SparseArray<UnclosedResourceException>> mResources = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<Class<?>, SparseArray<Exception>> mResources = new ConcurrentHashMap<>();
|
||||||
private static Handler mHandler;
|
private static Handler sHandler;
|
||||||
private static boolean mEnabled = false;
|
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) {
|
public static void onOpen(ResourceMonitor.Resource resource) {
|
||||||
if (!mEnabled) {
|
if (!mEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SparseArray<UnclosedResourceException> map = mResources.get(resource.getClass());
|
SparseArray<Exception> map = mResources.get(resource.getClass());
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = new SparseArray<>();
|
map = new SparseArray<>();
|
||||||
mResources.put(resource.getClass(), map);
|
mResources.put(resource.getClass(), map);
|
||||||
}
|
}
|
||||||
int resourceId = resource.getResourceId();
|
int resourceId = resource.getResourceId();
|
||||||
ResourceMonitor.UnclosedResourceException exception = new ResourceMonitor.UnclosedResourceException("id = " + resourceId + ", resource = " + resource);
|
Exception exception;
|
||||||
|
if (sExceptionCreator == null) {
|
||||||
|
exception = new ResourceMonitor.UnclosedResourceException(resource);
|
||||||
exception.fillInStackTrace();
|
exception.fillInStackTrace();
|
||||||
|
} else {
|
||||||
|
exception = sExceptionCreator.create(resource);
|
||||||
|
}
|
||||||
map.put(resourceId, exception);
|
map.put(resourceId, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,18 +62,25 @@ public final class ResourceMonitor {
|
|||||||
if (!mEnabled) {
|
if (!mEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SparseArray<UnclosedResourceException> map = mResources.get(resource.getClass());
|
SparseArray<Exception> map = mResources.get(resource.getClass());
|
||||||
if (map != null) {
|
if (map != null) {
|
||||||
int indexOfKey = map.indexOfKey(resource.getResourceId());
|
int indexOfKey = map.indexOfKey(resource.getResourceId());
|
||||||
if (indexOfKey >= 0) {
|
if (indexOfKey >= 0) {
|
||||||
final ResourceMonitor.UnclosedResourceException unclosedResourceException = map.valueAt(indexOfKey);
|
final Exception exception = map.valueAt(indexOfKey);
|
||||||
map.removeAt(indexOfKey);
|
map.removeAt(indexOfKey);
|
||||||
if (mHandler == null) {
|
if (sHandler == null) {
|
||||||
mHandler = new Handler(Looper.getMainLooper());
|
sHandler = new Handler(Looper.getMainLooper());
|
||||||
}
|
}
|
||||||
mHandler.post(new Runnable() {
|
sHandler.post(new Runnable() {
|
||||||
public final void run() {
|
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 static final class UnclosedResourceException extends RuntimeException {
|
||||||
public UnclosedResourceException(String message) {
|
public UnclosedResourceException(Resource resource) {
|
||||||
super(message);
|
super("id = " + resource.getResourceId() + ", resource = " + resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final class UnclosedResourceDetectedException extends RuntimeException {
|
public static final class UnclosedResourceDetectedException extends RuntimeException {
|
||||||
public UnclosedResourceDetectedException(ResourceMonitor.UnclosedResourceException cause) {
|
public UnclosedResourceDetectedException(Throwable cause) {
|
||||||
super(cause);
|
super(cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,4 +112,13 @@ public final class ResourceMonitor {
|
|||||||
public interface Resource {
|
public interface Resource {
|
||||||
int getResourceId();
|
int getResourceId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface ExceptionCreator {
|
||||||
|
Exception create(Resource resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface UnclosedResourceDetectedHandler {
|
||||||
|
|
||||||
|
void onUnclosedResourceDetected(UnclosedResourceDetectedException detectedException);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user