优化 captureScreen()返回null的问题

优化 ResourceMonitor的错误显示
This commit is contained in:
hyb1996
2018-10-31 14:02:50 +08:00
parent c92d869fa1
commit 65aeb754f2
5 changed files with 82 additions and 56 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;

View File

@@ -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");

View File

@@ -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);
}
} }