Android tomar captura de pantalla en dispositivo arraigado

ACTUALIZAR Hay una serie de otras publicaciones que preguntan cómo obtener una captura de pantalla en Android, pero ninguna parece tener una respuesta completa de cómo hacerlo. Originalmente, publiqué esto como una pregunta debido a un problema en particular que estaba encontrando al intentar abrir una secuencia en el Frame Buffer. Ahora he cambiado a volcar el Frame Buffer en un archivo, así que actualicé mi publicación para mostrar cómo llegué allí. Para referencia (y confirmación), encontré el comando para enviar el FrameBuffer a un archivo desdeesta publicación (desafortunadamente él no proporcionó cómo llegó a ese punto). Solo me estoy perdiendo la forma de convertir los datos sin procesar que obtuve del Frame Buffer en un archivo de imagen real.

Mi intención era hacer un volcado completo de la pantalla real en un dispositivo Android. lossolamente La forma en que podría encontrarlo sin usar el puente adb era acceder directamente al Frame Buffer del sistema. Obviamente, este enfoque requerirá privilegios de root en el dispositivo y para la aplicación que lo ejecuta. Afortunadamente para mis propósitos, tengo control sobre cómo se configura el Dispositivo y es factible tener el dispositivo enraizado con privilegios de root proporcionados a mi aplicación. Mis pruebas se están realizando actualmente en un Droid antiguo que funciona con 2.2.3.

Encontré mis primeros indicios de cómo abordarlo.https://stackoverflow.com/a/6970338/1446554. Después de un poco más de investigación, encontré otro artículo que describe cómoejecutar comandos de shell como root. Lo estaban usando para ejecutar un reinicio, yo lo uso para enviar el búfer de cuadros actual a un archivo real. Mis pruebas actuales solo han llegado tan lejos como para hacer esto a través de ADB y en una Actividad básica (a cada una se le proporciona una raíz). Haré más pruebas de un Servicio que se ejecuta en segundo plano, ¡las actualizaciones están por venir! Aquí está toda mi actividad de prueba que puede exportar la pantalla actual a un archivo:

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

Esto también requiere agregar elandroid.permission.WRITE_EXTERNAL_STORAGE Permiso al Manifiesto. Como se sugiere enesta publicación. De lo contrario, se ejecuta, no se queja, no crea los directorios ni el archivo.

Originalmente, no podía obtener datos utilizables del Frame Buffer debido a que no entendía cómo ejecutar correctamente los comandos de shell. Ahora que he cambiado a usar las secuencias para ejecutar comandos, puedo usar '>' para enviar los datos actuales del Frame Buffer a un archivo real ...

Respuestas a la pregunta(3)

Su respuesta a la pregunta