Zugriff per Reflection o.ä. möglich?

Status
Nicht offen für weitere Antworten.
T

tuxedo

Gast
Hallo,

ich benutze java.awt.Robot zum scraping des Desktops. Dummerweise gibts da aber ein kleines "Performanceproblem" mit dessen Implementierung:

Code:
/*
 * Copyright 1998-2006 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit [url]www.sun.com[/url] if you need additional information or
 * have any questions.
 */

package sun.awt.windows;

import java.awt.*;
import java.awt.peer.RobotPeer;

class WRobotPeer extends WObjectPeer implements RobotPeer
{
    WRobotPeer() {
        create();
    }
    WRobotPeer(GraphicsDevice screen) {
        create();
    }

    private synchronized native void _dispose();

    protected void disposeImpl() {
        _dispose();
    }

    public native void create();
    public native void mouseMoveImpl(int x, int y);
    public void mouseMove(int x, int y) {
        mouseMoveImpl(x, y);
    }
    public native void mousePress(int buttons);
    public native void mouseRelease(int buttons);
    public native void mouseWheel(int wheelAmt);

    public native void keyPress( int keycode );
    public native void keyRelease( int keycode );

    public int getRGBPixel(int x, int y) {
        return getRGBPixelImpl(x, y);
    }
    public native int getRGBPixelImpl(int x, int y);

    public int [] getRGBPixels(Rectangle bounds) {
        int pixelArray[] = new int[bounds.width*bounds.height];
        getRGBPixels(bounds.x, bounds.y, bounds.width, bounds.height, pixelArray);
        return pixelArray;
    }

    private native void getRGBPixels(int x, int y, int width, int height, int pixelArray[]);
}

Konkret geht es um die Methode "public int [] getRGBPixels(Rectangle bounds)" die vom Robot intern aufgerufen wird wenn man so einen Aufruf startet:

Code:
BufferedImage screenScrape = myRobot.createScreenCapture(screenRect);

Problem daran ist: Ich muss möglichst oft pro Sekunde den Desktop scrapen. Und die besagte Methode erzeugt eben bei jedem Aufruf ein neues "int pixelArray[]". Das kostet unnötig Zeit (und Nerven).

Die Idee ist jetzt, die native Methode "getRGBPixels(int x, int y, int width, int height, int pixelArray[])" selbst aufzurufen und das zu übergebene int[] zu recyclen statt immer neu zu erzeugen.

Problem ist jetzt eigentlich: Wie erzeuge ich eine Instanz der privaten Klasse WRobotPeer? Oder andersrum: Wie komm ich an diese Instanz die der Robot erzeugt ran?

Ich will möglichst keinen Sourcecode "kopieren" und auch keine eigene native Implementierung bauen. Schließlich soll die Anwendung ja mit jedem standard (6er) JRE laufen.

Gruß
Alex
 
S

SlaterB

Gast
wie jetzt, keine Ideen, Anfängerfrage, von dir?

Code:
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        Robot r = new Robot();
        Field f = r.getClass().getDeclaredField("peer");
        f.setAccessible(true);
        Object o = f.get(r);
        System.out.println(o + " - " + o.getClass());

        RobotPeer rp = (RobotPeer)o;
        int[] x = rp.getRGBPixels(new Rectangle(20, 20));
        System.out.println(Arrays.toString(x));
    }
}
 
T

tuxedo

Gast
Okay, bin selbst ein Stückchen weiter gekommen, aber am Ziel bin ich noch nicht.

Hab jetzt das hier gebastelt:

Code:
package sun.awt.windows;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.peer.RobotPeer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyRobotTest {
	
	public static void main(String[] args) throws AWTException, SecurityException, 
NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		Robot r = new Robot();
		
		Field peerField = Robot.class.getDeclaredField("peer");

		peerField.setAccessible(true);

		RobotPeer peer = (RobotPeer) peerField.get(r);
		
		System.out.println("peer = " + peer);
		
		sun.awt.windows.WRobotPeer wPeer = (sun.awt.windows.WRobotPeer) peer;
		
		Method[] privateStringMethod = sun.awt.windows.WRobotPeer.class.getMethods();

		Method myMethod = null;
		
		for (Method method : privateStringMethod) {
			if (method.toString().equals("private native void getRGBPixels(int x, int y, int width, int height, int pixelArray[])")) {
				myMethod = method;
				break;
			}
		}
		
		myMethod.setAccessible(true);

		int[] pixels = new int[3360*1050];
		
		myMethod.invoke(wPeer, 0,0,3360,1050, pixels);
		int i = 0;
		for (int y=0;y<1050;y++) {
			for (int x=0;x<3360;x++){
				System.out.print(i++ + " ");
			}
			System.out.println();
		}
	
		
	}

}

Wichitg schien zu sein, dass "MyRobotTest" im package "sun.awt.windows" liegt, sonst beschwert sich Eclipse noch vor dem compilieren mit "sun.awt.windows.WRobotPeer is not visible".

In dieser Konstellation beschwert sich Eclipse nun nicht mehr. Aber zur Laufzeit spuckt mir die Console folgendes aus (Zeilenangabe stimmt mit dem Samplecode überein):

peer = sun.awt.windows.WRobotPeer@16caf43
Exception in thread "main" java.lang.IllegalAccessError: tried to access class sun.awt.windows.WRobotPeer from class sun.awt.windows.MyRobotTest
at sun.awt.windows.MyRobotTest.main(MyRobotTest.java:23)

Any ideas?

@slater
Soweit war ich ja schon. Aber du hast die "falsche" Methode aufgerufen ...
 
R

Roar

Gast
Die Zeile
sun.awt.windows.WRobotPeer wPeer = (sun.awt.windows.WRobotPeer) peer;
brauchst du doch vermutlich gar nicht?
statt
sun.awt.windows.WRobotPeer.class.getMethods();
müsste auch
peer.getClass().getMethods();
ausreichen
 
S

SlaterB

Gast
update

Code:
        Class[] ck = new Class[]
            {int.class, int.class, int.class, int.class, int[].class};
        Method m = rp.getClass().getDeclaredMethod("getRGBPixels", ck);
        m.setAccessible(true);
        x = new int[200];
        m.invoke(rp, new Object[]
            {4, 5, 6, 7, x});
        System.out.println(Arrays.toString(x));
von 'normalen' package aus, wenn setAccessible(true); nicht reicht, dann fällt mir dazu nix weiter ein
 

Zed

Bekanntes Mitglied
Wie wäre es mit diesem Ansatz?

Eigene Klasse extends Robot
// Mit Copy & Pase überschreiben
public synchronized BufferedImage createScreenCapture(Rectangle screenRect) {

// Den Aufruf durch den gewünschten eigenen ersetzen.
pixels = peer.getRGBPixels(translatedRect)
 
R

Roar

Gast
tuxedo braucht allerdings die methode
private native void getRGBPixels(int x, int y, int width, int height, int pixelArray[]);
die ist nicht in RobotPeer definiert, die ist privat und in der packageprotecteten klasse WRobotPeer :(
Das mit dem toString() überprüfen klappt so wahrscheinlich auch nicht, lieber SlaterB's code dafür benutzen.
 
T

tuxedo

Gast
@Slater

setAccessible(true) reicht nicht. Irgendwas an der Tatsache dass "WRobotPeer" an sich private ist verhindert das laden der Klasse.

Hab bisher keine "private" Klassen benutzt oder gebraucht. Steh daher etwas auf dem Schlauch. Dachte eigentlich dass ich, wenn ich mich im gleichen Package befinde, die Klasse dann laden kann.

Oder ist der Classloader so schlau und weiß dass WRobotPeer und MyRobotTest zwar im gleichen Package, aber nicht im gleichen Verzeichnis sind, und verbietet deshalb den Zugriff?

@Alle anderen:

Copy&Paste -> Keine gute Idee. Allein schon aus Lizenzgründen (weiß noch nicht ob ich GPL benutzen will).
Klassen Überschreiben: Spätestens bei der privaten Klasse WRobotPeer funktioniert das nicht mehr so toll.
>> Das mit dem toString() überprüfen klappt so wahrscheinlich auch nicht, lieber SlaterB's code dafür benutzen.

Ich weiß, ist ja bisher auch noch stark "experimentell".

Ich tippe mal drauf dass ich den Classloader austricksen muss. Was meint ihr?

- Alex
 
S

SlaterB

Gast
deine Fehlermeldung erhalte ich auch, in Zeile
> sun.awt.windows.WRobotPeer wPeer = (sun.awt.windows.WRobotPeer) peer;

die Zeile ist aber gar nicht nötig, siehe meinen Code, der läuft (beide Postings zusammengesetzt)
 

HoaX

Top Contributor
wäre genauso gehacke, da peer private ist

evtl macht es sinn gleich das ganze selbst per jni/jna zu machen
 

byte

Top Contributor
tuxedo hat gesagt.:
setAccessible(true) reicht nicht. Irgendwas an der Tatsache dass "WRobotPeer" an sich private ist verhindert das laden der Klasse.

Hab bisher keine "private" Klassen benutzt oder gebraucht. Steh daher etwas auf dem Schlauch. Dachte eigentlich dass ich, wenn ich mich im gleichen Package befinde, die Klasse dann laden kann.

Oder ist der Classloader so schlau und weiß dass WRobotPeer und MyRobotTest zwar im gleichen Package, aber nicht im gleichen Verzeichnis sind, und verbietet deshalb den Zugriff?

Die Klasse ist aus einem sun. Package und daher nicht Teil der JDK API. Fliegt eine SecurityException? Normalerweise verhindert der SecurityManager, dass man von aussen auf solche Sun-Klassen zugreifen kann.

Würde mir übrigens zweimal überlegen, solche Schweinereien mit den Sun-Klassen zu implementieren, denn es ist nicht gewährleistet, dass sich diese Klassen nicht ändern. Selbst wenn Du oben beschriebenes Problem löst, dann läuft das ganze vielleicht mit dem nächsten Patch schon nicht mehr, weil Sun die Klassen geändert hat.
 
T

tuxedo

Gast
@Slater

Danke, das scheint zu funktionieren:

Code:
package sun.awt.windows;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.peer.RobotPeer;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyRobotTest {
	
	public static void main(String[] args) throws AWTException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, NoSuchMethodException {
		Robot r = new Robot();
		
		Field peerField = Robot.class.getDeclaredField("peer");

		peerField.setAccessible(true);

		RobotPeer peer = (RobotPeer) peerField.get(r);
		
		System.out.println("peer = " + peer);
		
		Class[] ck = new Class[]
		                       {int.class, int.class, int.class, int.class, int[].class};
		Method myMethod = peer.getClass().getDeclaredMethod("getRGBPixels", ck);
		myMethod.setAccessible(true);
		
		int width=100;
		int height=100;
		
		int[] pixels = new int[width*height];
		
		myMethod.invoke(peer, 0,0,width,height, pixels);
		int i = 0;
		for (int y=0;y<height;y++) {
			for (int x=0;x<width;x++){
				System.out.print(pixels[i++] + " ");
			}
			System.out.println();
		}
	
		
	}

}

Problem war scheinbar, dass ich den cast auf WRobotPeer gemacht habe. Bleibt man beim normalen "peer" Objekt welches sich in der Robot-Klasse befindet klappts.

Danke mal soweit. Jetzt kann ich meine Performance-Tests machen und schauen ob's tatsächlich schneller wird wenn ich nicht bei jeden Screenshot ein neues int[] für die Pixel brauche...

- Alex
 
T

tuxedo

Gast
In der Tat geht es etwas schneller. Aber nicht so schnell wie ich dachte:

Mit der "neuen" Methode bei der das int[] wiederverwendet wird braucht die Anwendung im Schnitt 71ms (1000 aufeinanderfolgende scrapes) pro Screenscrape eines 3360x1050 Desktops.

Auf "normalem" Weg braucht's 88ms. Hab also rund 19% Zeit gespart.

Im Profiler seh ich noch dass bei der "neuen" Methode der Heap konstanz bleibt. Wohin gegen der "normale" Weg nach rund 50sek ständig neuen Speicher reserviert und wieder freigibt. Ergibt einen schicken Sägezahn.

Denke da ist noch mehr "sparpotential" drin. Evtl doch weg von der Sun-Implementierung und eine eigene native Lib einbinden. Mal sehen.

- Alex

[update]
Bei einem 1920x1200 Desktop (ist denke ich das größe was ein 0815 Standardbenutzer eingestellt hat/einstellen kann [nicht jeder hat 2 Monitore..]), komme ich auf 45ms, bzw. 62ms. D.h. ich kann rund 22fps capturen. Okay, geht noch etwas Zeit flöten zum erkennen der "dirty rectangles" und zum aufbereiten der Daten für's Netzwerk. Aber ich denke 15..18fps wären durchaus möglich.

Damit wäre der Weg für eine brauchbare Java-only-VNC-like-Server-Implementierung geebnet ...
 
T

tuxedo

Gast
Naja, wäre etwas "überdimensioniert" für eine VNC-like Anwendung zwingend etwas größeres als einen 2Ghz Dualcore zu nehmen, oder?

Wobei ich ja momentan das ganze Single-Threaded laufen lasse.

Naja, bisher ist es eh mehr eine Spielerei als ein konkretes Vorhaben VNC neu zu erfinden.

- Alex
 

Zed

Bekanntes Mitglied
Die Frage ist was passiert wenn man den Deamon auf einem nicht gut dimensionierten Rechner laufen lässt und wie viel Systemressourcen da drauf gehen. Soweit ich weiß wird bei VNC nur das aktualisiert was sich geändert hat.
 
T

tuxedo

Gast
Jepp, deshalb hab ich auch eine Testimplementierung für eine "Dirty Rectangle Detection". Die Zeit die dafür nötig ist hab ich in den 15..18fps schon mit einkalkuliert.

- Alex
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
C Probleme mit dem Zugriff auf private Methode per reflection Allgemeine Java-Themen 2
C Zugriff auf private Methode per reflection geht nicht mehr Allgemeine Java-Themen 3
K Reflection:Zugriff auf innere Klassen Allgemeine Java-Themen 4
LucasGlockner Effizienter byte-Zugriff auf ein long[]-Array Allgemeine Java-Themen 8
W Klassen Zugriff auf ein Textfile aus allen Klassen. Allgemeine Java-Themen 2
izoards Zugriff auf gemeinsame Ressource (CSV-File) Allgemeine Java-Themen 3
S Java Zugriff auf Netzwerklaufwerk Allgemeine Java-Themen 1
sascha-sphw Java 9 module Zugriff auf eine resource einer anderen JAR Allgemeine Java-Themen 0
KeexZDeveoper Zugriff auf Methoden vom Server Allgemeine Java-Themen 7
O Zugriff auf mySQL ohne JDBC Allgemeine Java-Themen 3
P Element einer Liste wurde hinzugefügt, aber es gibt keinen Zugriff Allgemeine Java-Themen 2
B Maven Zugriff auf files aus einem kompilierten jar Allgemeine Java-Themen 15
S Zugriff auf jUnit Test Suite Runner-Instanzen innerhalb von Test Classes Allgemeine Java-Themen 7
W Zugriff auf Objektvariablen vs. Übergabe Allgemeine Java-Themen 3
J Zugriff auf erstellte Objekte einer Klasse von einer Klasse ausserhalb Allgemeine Java-Themen 3
Tommy Nightmare HTTP Zugriff auf Internetseite im Loginbereich Allgemeine Java-Themen 5
H Zugriff auf PHP Allgemeine Java-Themen 4
B DB-Zugriff einer Webanwendung funktioniert nicht mit Java 7 Allgemeine Java-Themen 2
M WebService - Zugriff auf Webservice Methode über Browser Allgemeine Java-Themen 1
O JNA Zugriff auf Funktion aus DLL Allgemeine Java-Themen 0
O Zugriff auf Windows Zertifikatstore Allgemeine Java-Themen 2
M Kein Zugriff auf microSD Karten Allgemeine Java-Themen 4
T Zugriff auf Datenbank Allgemeine Java-Themen 1
J Zugriff auf IMAP GMail Konto scheitert. Allgemeine Java-Themen 2
P Frontend- Zugriff auf WS- Backend Allgemeine Java-Themen 0
U Zugriff auf Datei sperren Allgemeine Java-Themen 5
N Best Practice Semi-Synchronized Zugriff Allgemeine Java-Themen 0
C Zugriff auf Event felder Allgemeine Java-Themen 0
M Threads synchroner Zugriff (add/delete/read) auf eine Liste Allgemeine Java-Themen 6
F Zugriff Verweigert bei Kopieroperation? Allgemeine Java-Themen 4
T JNI: kein Zugriff auf VM in Callback-Methode eines Windows-Hooks Allgemeine Java-Themen 3
S Dynamischer Zugriff Allgemeine Java-Themen 4
Minonos Einem Programm Zugriff auf bestimmte Ordner geben Allgemeine Java-Themen 5
E Zugriff auf Dateien im Filesystem überwachen Allgemeine Java-Themen 5
H Programierstil: static - Zugriff vs. Staticzugriff Allgemeine Java-Themen 24
V Zugriff auf den Objekterzeuger? Allgemeine Java-Themen 4
M Zugriff zweier Threads auf diesselbe Methode Allgemeine Java-Themen 16
B Zugriff auf eine HashMap Allgemeine Java-Themen 4
B JApplet Zugriff auf Local Storage des Browser? Allgemeine Java-Themen 2
D Zugriff auf Array-Liste Allgemeine Java-Themen 19
M gleichzeitiger Zugriff auf eine Textdatei Allgemeine Java-Themen 6
D Eclipse Kein Zugriff auf Inhalt einer referenzierten .jar Allgemeine Java-Themen 5
B synchronisierter zugriff auf Objekt Allgemeine Java-Themen 6
nutellastulle Zugriff, Übergabe, Bearbeitung und Ausgabe von Jlist Allgemeine Java-Themen 6
U Große Liste von Strings mit indiziertem Zugriff Allgemeine Java-Themen 31
J XML Element Zugriff Allgemeine Java-Themen 4
P Daten kopieren mit nio - Zugriff verweigert Allgemeine Java-Themen 8
M Klassen Zugriff auf getMethode ohne Klasse zu erzeugen Allgemeine Java-Themen 6
A Input/Output Applet-Zugriff auf PHP-Schnittstelle (externer Server) Allgemeine Java-Themen 22
H Vererbung Abgeleitete Klassen und Zugriff Allgemeine Java-Themen 2
J Zugriff auf Poker-Client Fenster Allgemeine Java-Themen 14
S Zugriff auf innere Klasse Allgemeine Java-Themen 3
D Kein Zugriff auf WebService ausser localhost Allgemeine Java-Themen 4
Sonecc Zugriff auf Class File einer anderen Jar während der Laufzeit Allgemeine Java-Themen 2
J Zugriff auf Dateien auf einem shared Folder? Allgemeine Java-Themen 3
H Zugriff auf VBA in Java Allgemeine Java-Themen 2
Haave Audio Device Unavailable: Kein gleichzeitiger Zugriff auf Soundsystem möglich Allgemeine Java-Themen 7
G Letzter Zugriff auf Datei Allgemeine Java-Themen 5
C java.io.FileNotFoundException: (Zugriff verweigert) Allgemeine Java-Themen 14
O Zugriff auf Serielle Schnittstelle - Keine Ports gefunden. Allgemeine Java-Themen 8
C Webstart: Zugriff auf lokale Dateien? Allgemeine Java-Themen 2
X Zugriff auf ComboBoxen in Hauptklasse von zweiter Klasse aus Allgemeine Java-Themen 8
J Zugriff auf gemeinsame Funktionen Allgemeine Java-Themen 4
Airwolf89 Zugriff auf ArrayList<ArrayList> Allgemeine Java-Themen 3
Airwolf89 Zugriff auf Werte in ArrayList<ArrayList> Allgemeine Java-Themen 4
T Zugriff zwischen Klassen für repaint Allgemeine Java-Themen 7
N Zugriff auf eine Referenzvar. Allgemeine Java-Themen 3
S Zugriff auf Klasse Allgemeine Java-Themen 4
Meldanor Mehrdimensionale Arrays : Zugriff auf n-tes Array Allgemeine Java-Themen 5
E JNA:Zugriff auf Common-Block von Fortran bzw. Struct in C Allgemeine Java-Themen 2
T Zugriff auf Singleton verkürzen - Namespaces?? Allgemeine Java-Themen 20
L Zugriff auf ein Objekt mit mehreren Threads Allgemeine Java-Themen 11
Airwolf89 dynamischer Zugriff auf Variablen/ Objekte Allgemeine Java-Themen 4
S Zugriff auf einzelne Bildpunkte Allgemeine Java-Themen 3
D Referenzen weiterreichen vs. statischer Zugriff Allgemeine Java-Themen 3
V Zugriff auf Default-Package? Allgemeine Java-Themen 6
P RegeEx-Problem: Zugriff auf group Allgemeine Java-Themen 2
M Zugriff auf Parallel-Schnittstelle Allgemeine Java-Themen 2
B Zugriff mit einem Applet auf den Datenträger Allgemeine Java-Themen 11
S Innere Klasse: Zugriff auf äußere Variable Allgemeine Java-Themen 5
I Zugriff auf Daten Allgemeine Java-Themen 5
D Zugriff auf Windows Dienste Allgemeine Java-Themen 7
G Zugriff auf Memberclasses einer geladenen Class-Datei Allgemeine Java-Themen 2
I Gleichzeitiger zugriff auf ein Long über Threads Allgemeine Java-Themen 2
P Wieso HashMap-Zugriff mit Object, statt mit MyObject? Allgemeine Java-Themen 12
J Kein Zugriff auf Klassen im Default Package Allgemeine Java-Themen 8
M Paralleler Zugriff auf statische Methode Allgemeine Java-Themen 5
S Zugriff auf unterschiedliche JREs Allgemeine Java-Themen 7
M "Unzulässiger Zugriff auf einen Speicherbereich" Allgemeine Java-Themen 7
A Zugriff auf Parallelport nur über Eclipse nicht über .jar ! Allgemeine Java-Themen 12
G Zugriff auf ein sama share Allgemeine Java-Themen 8
J Java zugriff auf Exchange Server Allgemeine Java-Themen 10
D eclipse: Zugriff auf Ordner per code Allgemeine Java-Themen 4
O Konkurrierender Zugriff auf Log-Datei mit Log4J Allgemeine Java-Themen 11
Caracasa [Threads] Gleichzeitiger Zugriff auf eine LinkedList Allgemeine Java-Themen 9
L Zugriff auf Objekt das sich in einer Liste befindet Allgemeine Java-Themen 2
J Zugriff auf den Namen einer Variablen Allgemeine Java-Themen 7
J Zugriff auf Map in anderer Klasse Allgemeine Java-Themen 2
J Endlosschleife durch wechselseitigen Zugriff zweier Klassen? Allgemeine Java-Themen 2
F Zugriff auf lokalen Rechner wer weiss Rat ? Allgemeine Java-Themen 16

Ähnliche Java Themen

Neue Themen


Oben