Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8298101

Robot.createScreenCapture() cause frame block on uos(kirin cpu) linux

XMLWordPrintable

    • x86_64
    • linux

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


            pnarayanaswa Praveen Narayanaswamy
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: