JDK-8298101 : Robot.createScreenCapture() cause frame block on uos(kirin cpu) linux
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86_64
  • Submitted: 2022-12-01
  • Updated: 2022-12-05
  • Resolved: 2022-12-05
Related Reports
Duplicate :  
Description
ADDITIONAL SYSTEM INFORMATION :
OS: uos, a chinese linux.
CPU:Kirin, a chinese cpu(arm64/aarch64)

A DESCRIPTION OF THE PROBLEM :
We use Robot to capture srceen, and blocked.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1, Running the test code

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Can move mouse
ACTUAL -
Can't move mouse.

---------- BEGIN SOURCE ----------
public class ScreenShot extends JFrame
{
	private static Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
	
	public ScreenShot()
	{
        Rectangle rectangle = new Rectangle(dimension.width, dimension.height);
        try
        {
        	Robot robot = new Robot();
        	BufferedImage image = robot.createScreenCapture(rectangle);
        }
        catch (Exception e)
        {
        	e.printStackTrace();
        }
	}
	
	public static void main(String[] args)
	{
		ScreenShot ss = new ScreenShot();
		ss.setSize(dimension.width, dimension.height);
		ss.setVisible(true);
	}

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
awt_Robot.c

#ifdef HEADLESS
    #error This file should not be included in headless library
#endif

#include "jvm_md.h"
#include <dlfcn.h>

#include "awt_p.h"
#include "awt_GraphicsEnv.h"
#define XK_MISCELLANY
#include <X11/keysymdef.h>
#include <X11/Intrinsic.h>
#include <X11/Xutil.h>
#include <X11/Xmd.h>
#include <X11/extensions/xtestext1.h>
#include <X11/extensions/XTest.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XI.h>
#include <jni.h>
#include <sizecalc.h>
#include "canvas.h"
#include "wsutils.h"
#include "list.h"
#include "multiVis.h"

#include "java_awt_event_InputEvent.h"

#if defined(__linux__) || defined(MACOSX)
#include <sys/socket.h>
#endif

static Bool   (*compositeQueryExtension)       (Display*, int*, int*);
static Status (*compositeQueryVersion)         (Display*, int*, int*);
static Window (*compositeGetOverlayWindow)     (Display*, Window);
static Window (*compositeReleaseOverlayWindow) (Display*, Window);

extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs;

static jint * masks;
static jint num_buttons;

static void *xCompositeHandle;

static const char* XCOMPOSITE = JNI_LIB_NAME("Xcomposite");
static const char* XCOMPOSITE_VERSIONED = VERSIONED_JNI_LIB_NAME("Xcomposite", "1");

static Bool checkXCompositeFunctions(void) {
    return (compositeQueryExtension   != NULL   &&
            compositeQueryVersion     != NULL   &&
            compositeGetOverlayWindow != NULL);
}

static void initXCompositeFunctions(void) {

    if (xCompositeHandle == NULL) {
        xCompositeHandle = dlopen(XCOMPOSITE, RTLD_LAZY | RTLD_GLOBAL);
        if (xCompositeHandle == NULL) {
            xCompositeHandle = dlopen(XCOMPOSITE_VERSIONED, RTLD_LAZY | RTLD_GLOBAL);
        }
    }
    //*(void **)(&asyncGetCallTraceFunction)
    if (xCompositeHandle != NULL) {
        *(void **)(&compositeQueryExtension)       = dlsym(xCompositeHandle, "XCompositeQueryExtension");
        *(void **)(&compositeQueryVersion)         = dlsym(xCompositeHandle, "XCompositeQueryVersion");
        *(void **)(&compositeGetOverlayWindow)     = dlsym(xCompositeHandle, "XCompositeGetOverlayWindow");
        *(void **)(&compositeReleaseOverlayWindow) = dlsym(xCompositeHandle, "XCompositeReleaseOverlayWindow");
    }

    if (xCompositeHandle && !checkXCompositeFunctions()) {
        dlclose(xCompositeHandle);
    }
}

static int32_t isXTestAvailable() {
    int32_t major_opcode, first_event, first_error;
    int32_t  event_basep, error_basep, majorp, minorp;
    int32_t isXTestAvailable;

    /* check if XTest is available */
    isXTestAvailable = XQueryExtension(awt_display, XTestExtensionName, &major_opcode, &first_event, &first_error);
    if (isXTestAvailable) {
        DTRACE_PRINTLN3("RobotPeer: XQueryExtension(XTEST) returns major_opcode = %d, first_event = %d, first_error = %d",
                        major_opcode, first_event, first_error);
        /* check if XTest version is OK */
        XTestQueryExtension(awt_display, &event_basep, &error_basep, &majorp, &minorp);
        DTRACE_PRINTLN4("RobotPeer: XTestQueryExtension returns event_basep = %d, error_basep = %d, majorp = %d, minorp = %d",
                        event_basep, error_basep, majorp, minorp);
        if (majorp < 2 || (majorp == 2 && minorp < 2)) {
            /* bad version*/
            DTRACE_PRINTLN2("XRobotPeer: XTEST version is %d.%d \n", majorp, minorp);
            if (majorp == 2 && minorp == 1) {
                DTRACE_PRINTLN("XRobotPeer: XTEST is 2.1 - no grab is available\n");
            } else {
                isXTestAvailable = False;
            }
        } else {
            /* allow XTest calls even if someone else has the grab; e.g. during
             * a window resize operation. Works only with XTEST2.2*/
            XTestGrabControl(awt_display, True);
        }
    } else {
        DTRACE_PRINTLN("RobotPeer: XTEST extension is unavailable");
    }

    return isXTestAvailable;
}

static Bool hasXCompositeOverlayExtension(Display *display) {

    int xoverlay = False;
    int eventBase, errorBase;
    if (checkXCompositeFunctions() &&
        compositeQueryExtension(display, &eventBase, &errorBase))
    {
        int major = 0;
        int minor = 0;

        compositeQueryVersion(display, &major, &minor);
        if (major > 0 || minor >= 3) {
            xoverlay = True;
        }
    }

    return xoverlay;
}

static jboolean isXCompositeDisplay(Display *display, int screenNumber) {

    char NET_WM_CM_Sn[25];
    snprintf(NET_WM_CM_Sn, sizeof(NET_WM_CM_Sn), "_NET_WM_CM_S%d\0", screenNumber);

    Atom managerSelection = XInternAtom(display, NET_WM_CM_Sn, 0);
    Window owner = XGetSelectionOwner(display, managerSelection);

    return owner != 0;
}

static XImage *getWindowImage(Display * display, Window window,
                              int32_t x, int32_t y,
                              int32_t w, int32_t h) {
    XImage         *image;
    int32_t        transparentOverlays;
    int32_t        numVisuals;
    XVisualInfo    *pVisuals;
    int32_t        numOverlayVisuals;
    OverlayInfo    *pOverlayVisuals;
    int32_t        numImageVisuals;
    XVisualInfo    **pImageVisuals;
    list_ptr       vis_regions;    /* list of regions to read from */
    list_ptr       vis_image_regions ;
    int32_t        allImage = 0 ;
    int32_t        format = ZPixmap;

    /* prevent user from moving stuff around during the capture */
    XGrabServer(display);

    /*
     * The following two functions live in multiVis.c-- they are pretty
     * much verbatim taken from the source to the xwd utility from the
     * X11 source. This version of the xwd source was somewhat better written
     * for reuse compared to Sun's version.
     *
     *        ftp.x.org/pub/R6.3/xc/programs/xwd
     *
     * We use these functions since they do the very tough job of capturing
     * the screen correctly when it contains multiple visuals. They take into
     * account the depth/colormap of each visual and produce a capture as a
     * 24-bit RGB image so we don't have to fool around with colormaps etc.
     */

    GetMultiVisualRegions(
        display,
        window,
        x, y, w, h,
        &transparentOverlays,
        &numVisuals,
        &pVisuals,
        &numOverlayVisuals,
        &pOverlayVisuals,
        &numImageVisuals,
        &pImageVisuals,
        &vis_regions,
        &vis_image_regions,
        &allImage );

    image = ReadAreaToImage(
        display,
        window,
        x, y, w, h,
        numVisuals,
        pVisuals,
        numOverlayVisuals,
        pOverlayVisuals,
        numImageVisuals,
        pImageVisuals,
        vis_regions,
        vis_image_regions,
        format,
        allImage );

    /* allow user to do stuff again */
    XUngrabServer(display);

    /* make sure the grab/ungrab is flushed */
    XSync(display, False);

    return image;
}

/*********************************************************************************************/

// this should be called from XRobotPeer constructor
JNIEXPORT void JNICALL
Java_sun_awt_X11_XRobotPeer_setup (JNIEnv * env, jclass cls, jint numberOfButtons, jintArray buttonDownMasks)
{
    int32_t xtestAvailable;
    jint *tmp;
    int i;

    DTRACE_PRINTLN("RobotPeer: setup()");

    num_buttons = numberOfButtons;
    tmp = (*env)->GetIntArrayElements(env, buttonDownMasks, JNI_FALSE);
    CHECK_NULL(tmp);

    masks = (jint *)SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(jint), num_buttons);
    if (masks == (jint *) NULL) {
        (*env)->ExceptionClear(env);
        (*env)->ReleaseIntArrayElements(env, buttonDownMasks, tmp, 0);
        JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), NULL);
        return;
    }
    for (i = 0; i < num_buttons; i++) {
        masks[i] = tmp[i];
    }
    (*env)->ReleaseIntArrayElements(env, buttonDownMasks, tmp, 0);

    AWT_LOCK();
    xtestAvailable = isXTestAvailable();
    DTRACE_PRINTLN1("RobotPeer: XTest available = %d", xtestAvailable);
    if (!xtestAvailable) {
        JNU_ThrowByName(env, "java/awt/AWTException", "java.awt.Robot requires your X server support the XTEST extension version 2.2");
    }

    AWT_UNLOCK();
}


JNIEXPORT int JNICALL
Java_sun_awt_X11_XRobotPeer_getRGBPixelsImpl( JNIEnv *env,
                             jclass cls,
                             jobject xgc,
                             jint x,
                             jint y,
                             jint width,
                             jint height,
                             jintArray pixelArray) {

    XImage *image;
    jint *ary;               /* Array of jints for sending pixel values back
                              * to parent process.
                              */
    Window rootWindow;
    AwtGraphicsConfigDataPtr adata;
    int compositeFlag = 0;

    DTRACE_PRINTLN6("RobotPeer: getRGBPixelsImpl(%lx, %d, %d, %d, %d, %x)", xgc, x, y, width, height, pixelArray);

    AWT_LOCK();

    /* avoid a lot of work for empty rectangles */
    if ((width * height) == 0) {
        AWT_UNLOCK();
        return;
    }
    DASSERT(width * height > 0); /* only allow positive size */

    adata = (AwtGraphicsConfigDataPtr) JNU_GetLongFieldAsPtr(env, xgc, x11GraphicsConfigIDs.aData);
    DASSERT(adata != NULL);

    rootWindow = XRootWindow(awt_display, adata->awt_visInfo.screen);
    if (hasXCompositeOverlayExtension(awt_display) &&
        isXCompositeDisplay(awt_display, adata->awt_visInfo.screen))
    {
        compositeFlag = 1;
        rootWindow = compositeGetOverlayWindow(awt_display, rootWindow);
    }

    image = getWindowImage(awt_display, rootWindow, x, y, width, height);
    if (image == NULL)
    {
        if (compositeFlag)
        {
            compositeReleaseOverlayWindow(awt_display, rootWindow);
        }
        AWT_UNLOCK();
        return 0;
    }

    /* Array to use to crunch around the pixel values */
    if (!IS_SAFE_SIZE_MUL(width, height) ||
        !(ary = (jint *) SAFE_SIZE_ARRAY_ALLOC(malloc, width * height, sizeof (jint))))
    {
        JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
        XDestroyImage(image);
        if (compositeFlag)
        {
            compositeReleaseOverlayWindow(awt_display, rootWindow);
        }
        AWT_UNLOCK();
        return 0;
    }
    /* convert to Java ARGB pixels */
    for (y = 0; y < height; y++) {
        for (x = 0; x < width; x++) {
            jint pixel = (jint) XGetPixel(image, x, y); /* Note ignore upper
                                                         * 32-bits on 64-bit
                                                         * OSes.
                                                         */

            pixel |= 0xff000000; /* alpha - full opacity */

            ary[(y * width) + x] = pixel;
        }
    }
    (*env)->SetIntArrayRegion(env, pixelArray, 0, height * width, ary);
    free(ary);

    XDestroyImage(image);
    if (compositeFlag)
    {
        compositeReleaseOverlayWindow(awt_display, rootWindow);
    }

    AWT_UNLOCK();
    return (height * width);
}



Comments
Duplicate of JDK-8269245
05-12-2022