Android toma una captura de pantalla en un dispositivo enraizado

ACTUALIZACIÓN Hay un número de otros puestos preguntando cómo obtener una captura de pantalla en android, pero ninguno parecía tener una respuesta completa de cómo hacerlo. Originalmente publiqué esto como una pregunta debido a una edición particular que funcionaba mientras que intentaba abrir una corriente al amortiguador del capítulo. Ahora he cambiado a dumping el búfer del marco a un archivo así que he puesto al día mi poste para demostrar cómo conseguí allí. Para referencia (y reconocimiento), encontré el comando para enviar el FrameBuffer a un archivo de esta publicación (por desgracia no proporcionó cómo llegó a ese punto). Sólo estoy perdiendo cómo convertir los datos sin procesar que extraje de la memoria intermedia de marco en un archivo de imagen real.

Mi intención era tomar un volcado completo de la pantalla real en un dispositivo Android. La única manera que pude encontrar para hacerlo sin usar el puente adb era acceder directamente al Buffer de marco 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 tener el dispositivo enraizado con privilegios de root proporcionados a mi aplicación es factible. Mi prueba se está realizando actualmente en un viejo Droid que ejecuta 2.2.3.

Encontré mis primeras sugerencias sobre cómo abordarlo desde https://stackoverflow.com/a/6970338/1446554 . Después de un poco más de investigación encontré otro artículo que describe cómo ejecutar correctamente los comandos shell como root . Lo estaban utilizando para ejecutar un reinicio, lo utilizo para enviar el búfer de cuadro actual a un archivo real. Mis pruebas actuales sólo han llegado hasta el punto de hacerlo a través de ADB y en una actividad básica (cada raíz proporcionada). Voy a hacer más pruebas de un servicio de ejecución en el fondo, las actualizaciones a venir! Aquí está mi actividad de prueba completa 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 el permiso android.permission.WRITE_EXTERNAL_STORAGE al Manifiesto. Como se sugiere en este post . De lo contrario se ejecuta, no se queja, no crea los directorios ni el archivo.

Originalmente no pude obtener datos utilizables desde el Buffer de trama debido a no entender cómo ejecutar correctamente comandos de shell. Ahora que he cambiado a usar las corrientes para ejecutar comandos puedo usar '>' para enviar los datos actuales de la memoria intermedia de marco a un archivo real …

Eso sería diferente para los diferentes teléfonos. Depende del formato gráfico subyacente de su dispositivo. Puede consultar qué formato de gráficos utiliza las llamadas al sistema. Si sólo va a ejecutar esto en los dispositivos que usted conoce el formato gráfico de usted puede escribir un convertidor que lo convierte en un formato conocido.

Puedes echar un vistazo al siguiente proyecto: http://code.google.com/p/android-fb2png/

Si observa el código fuente de fb2png.c, puede ver que encuesta FBIOGET_VSCREENINFO que contiene información acerca de cómo el dispositivo almacena la imagen de la pantalla en la memoria. Una vez que lo sepas, deberías poder convertirlo en un formato que puedas usar.

Espero que esto ayude.

Programáticamente puede ejecutar "adb shell / system / bin / screencap -p /sdcard / img.png" como se muestra a continuación:

 Process sh = Runtime.getRuntime().exec("su", null,null); OutputStream os = sh.getOutputStream(); os.write(("/system/bin/screencap -p " + "/sdcard/img.png").getBytes("ASCII")); os.flush(); os.close(); sh.waitFor(); 

Una solución fácil para los dispositivos ICS es utilizar lo siguiente desde la línea de comandos

 adb shell /system/bin/screencap -p /sdcard/screenshot.png adb pull /sdcard/screenshot.png screenshot.png 

Esto salvará el archivo screenshot.png en el directorio actual.

Probado en un Samsung Galaxy SII que ejecuta 4.0.3.

  • Detectar intentos de captura de pantalla en Android 4.0+
  • Captura de pantalla automática de la aplicación android en ejecución para el compromiso de la tienda de aplicaciones
  • Grabación de pantalla en la aplicación en Android para capturar 15 fotogramas por segundo
  • captura de pantalla de SurfaceControl android return null
  • ¿Existe un cliente / servidor Miracast para Mac o Windows?
  • Pantalla de captura de GLSurfaceView a mapa de bits
  • Capture la pantalla de Android y cree el video programáticamente
  • Toma la captura de pantalla de cualquier pantalla
  • No se puede tomar la captura de pantalla en Android L mediante programación
  • Pantalla de captura de pantalla del dispositivo Android Studio Emulator no disponible
  • Cómo capturar todo lo que se muestra actualmente en la pantalla, incluidos los cuadros de diálogo
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.