Android Screenshot auf gerootetem Gerät machen

AKTUALISIEREN Es gab eine Reihe anderer Beiträge, in denen gefragt wurde, wie man einen Screenshot in Android erstellt, aber keiner schien eine vollständige Antwort darauf zu haben. Ursprünglich habe ich dies als Frage gepostet, da ich auf ein bestimmtes Problem gestoßen bin, als ich versucht habe, einen Stream für den Frame Buffer zu öffnen. Jetzt habe ich den Frame Buffer in eine Datei kopiert und meinen Beitrag aktualisiert, um zu zeigen, wie ich dahin gekommen bin. Als Referenz (und Bestätigung) habe ich den Befehl gefunden, den FrameBuffer an eine Datei von zu sendendieser Beitrag (Leider hat er nicht angegeben, wie er zu diesem Punkt gekommen ist). Mir fehlt nur, wie ich die Rohdaten, die ich aus dem Frame Buffer gezogen habe, in eine tatsächliche Bilddatei verwandeln kann.

Meine Absicht war es, auf einem Android-Gerät einen vollständigen Speicherauszug des tatsächlichen Bildschirms zu erstellen. Dasnur Ein Weg, den ich finden konnte, ohne die ADB-Brücke zu verwenden, bestand darin, direkt auf den Frame-Puffer des Systems zuzugreifen. Offensichtlich erfordert dieser Ansatz Root-Rechte auf dem Gerät und für die App, die es ausführt! Glücklicherweise habe ich für meine Zwecke die Kontrolle darüber, wie das Gerät eingerichtet wird, und es ist machbar, dass das Gerät mit Root-Rechten gerootet wird, die für meine Anwendung bereitgestellt werden. Meine Tests werden derzeit auf einem alten Droid durchgeführt, auf dem 2.2.3 ausgeführt wird.

Ich fand meine ersten Hinweise, wie ich es angehen solltehttps://stackoverflow.com/a/6970338/1446554. Nach ein bisschen mehr Recherche habe ich einen weiteren Artikel gefunden, der beschreibt, wie man richtig vorgehtFühren Sie Shell-Befehle als root aus. Sie benutzten es, um einen Neustart durchzuführen. Ich benutzte es, um den aktuellen Bildpuffer an eine tatsächliche Datei zu senden. Meine aktuellen Tests haben dies nur über ADB und in einer grundlegenden Aktivität (die jeweils als Root bereitgestellt werden) erreicht. Ich werde weitere Tests von einem Dienst durchführen, der im Hintergrund ausgeführt wird, Updates folgen! Hier ist meine gesamte Testaktivität, die den aktuellen Bildschirm in eine Datei exportieren kann:

public class ScreenshotterActivity extends Activity {
    public static final String TAG = "ScreenShotter";

    private Button _SSButton;
    private PullScreenAsyncTask _Puller;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        _SSButton = (Button)findViewById(R.id.main_screenshotButton);
        _SSButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                if (_Puller != null)
                    return;
                //TODO: Verify that external storage is available! Could always use internal instead...

                _Puller = new PullScreenAsyncTask();
                _Puller.execute((Void[])null);
            }
        });
    }

    private void runSuShellCommand(String cmd) {
        Runtime runtime = Runtime.getRuntime();
        Process proc = null;
        OutputStreamWriter osw = null;
        StringBuilder sbstdOut = new StringBuilder();
        StringBuilder sbstdErr = new StringBuilder();

        try { // Run Script
            proc = runtime.exec("su");
            osw = new OutputStreamWriter(proc.getOutputStream());
            osw.write(cmd);
            osw.flush();
            osw.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (osw != null) {
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();                    
                }
            }
        }

        try {
            if (proc != null)
                proc.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        sbstdOut.append(readBufferedReader(new InputStreamReader(proc.getInputStream())));
        sbstdErr.append(readBufferedReader(new InputStreamReader(proc.getErrorStream())));
    }

    private String readBufferedReader(InputStreamReader input) {

        BufferedReader reader = new BufferedReader(input);
        StringBuilder found = new StringBuilder();
        String currLine = null;
        String sep = System.getProperty("line.separator");
        try {
            // Read it all in, line by line.
            while ((currLine = reader.readLine()) != null) {
                found.append(currLine);
                found.append(sep);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    class PullScreenAsyncTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {

            File ssDir = new File(Environment.getExternalStorageDirectory(), "/screenshots");
            if (ssDir.exists() == false) {
                Log.i(TAG, "Screenshot directory doesn't already exist, creating...");
                if (ssDir.mkdirs() == false) {
                    //TODO: We're kinda screwed... what can be done?
                    Log.w(TAG, "Failed to create directory structure necessary to work with screenshots!");
                    return null;
                }
            }
            File ss = new File(ssDir, "ss.raw");            
            if (ss.exists() == true) {
                ss.delete();
                Log.i(TAG, "Deleted old Screenshot file.");
            }
            String cmd = "/system/bin/cat /dev/graphics/fb0 > "+ ss.getAbsolutePath();
            runSuShellCommand(cmd);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            _Puller = null;
        }
    }
}

Dies erfordert auch das Hinzufügen derandroid.permission.WRITE_EXTERNAL_STORAGE Erlaubnis zum Manifest. Wie in vorgeschlagendieser Beitrag. Ansonsten läuft es, beschwert sich nicht, erstellt weder die Verzeichnisse noch die Datei.

Ursprünglich konnte ich keine verwendbaren Daten aus dem Frame Buffer abrufen, da ich nicht verstehe, wie Shell-Befehle richtig ausgeführt werden. Jetzt, da ich die Streams zum Ausführen von Befehlen verwendet habe, kann ich '>' verwenden, um die aktuellen Daten des Frame-Puffers an eine aktuelle Datei zu senden ...

Antworten auf die Frage(3)

Ihre Antwort auf die Frage