Native Crash en Android 4.3 al llamar a Picture.writeToStream ()

Una regresión se ha introducido en Android 4.3. Código que se utiliza para trabajar en versiones anteriores de Android ahora provoca un fallo nativo que cierra el proceso.

El bloqueo se produce cuando se dibuja una imagen que es mayor de 32 kb en un lienzo que está siendo grabado por un objeto de Picture que a su vez está escrito en una secuencia a través de writeToStream() .

El desplome está ocurriendo abajo en Skia al intentar escribir lejos una secuencia (que creo es el Uri del objeto de la imagen).

 I/DEBUG(122): #00 pc 0001e3bc /system/lib/libc.so (strlen+72) I/DEBUG(122): #01 pc 000d9858 /system/lib/libskia.so (SkWriter32::writeString(char const*, unsigned int)+256) I/DEBUG(122): #02 pc 00113d68 /system/lib/libskia.so (SkImageRef_ashmem::flatten(SkFlattenableWriteBuffer&) const+44) 

El programa siguiente muestra cómo reproducir este problema. Todo lo que se necesita es un diseño con un botón que tiene el 'botón' de identificación.

  public class MainActivity extends Activity { static final String IMAGE_FILE = Environment.getExternalStorageDirectory() + "/test.jpg"; static final String SKIA_FILE = Environment.getExternalStorageDirectory() + "/test.skia"; private static Bitmap loadBitmap(final String filename) { Bitmap bitmap = null; FileInputStream is; try { is = new FileInputStream(filename); final BitmapFactory.Options options = new BitmapFactory.Options(); options.inInputShareable = true; options.inPurgeable = true; bitmap = BitmapFactory.decodeFileDescriptor(is.getFD(), null, options); is.close(); } catch (final FileNotFoundException e) { e.printStackTrace(); } catch (final IOException ex) { ex.printStackTrace(); } return bitmap; } @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(final View v) { final Runnable runnable = new Runnable() { @Override public void run() { // Create a Canvas and begin recording final Picture picture = new Picture(); final Canvas canvas = picture.beginRecording(1024, 1024); // De-compress an image from file final Bitmap bitmap = loadBitmap(IMAGE_FILE); // If present draw the image to the canvas and end // recording if (bitmap != null) { canvas.drawBitmap(bitmap, new Matrix(), null); } picture.endRecording(); // Write out the Picture object to a Skia File. FileOutputStream os; try { os = new FileOutputStream(SKIA_FILE); picture.writeToStream(os); os.close(); } catch (final FileNotFoundException e) { e.printStackTrace(); } catch (final IOException ex) { ex.printStackTrace(); } } }; new Thread(runnable).start(); } }); } } 

Las dos líneas que definen el BitmapFactory.Options son necesarias para obtener el código de aplanamiento Skia para escribir los datos de imagen (de lo contrario se emiten las imágenes).

 options.inInputShareable = true; options.inPurgeable = true; 

Soy consciente de que los métodos Picture writeToStream() y createFromStream() han sido obsoletos, pero no espero que esto introduzca un problema de estabilidad.

Necesito anular el objeto de imagen, ya que quiero pasarlo de la aplicación principal a un proceso de servicio. No puedo utilizar la solución recomendada en la documentación que dice "dibujar la imagen en un mapa de bits" por las razones siguientes:

  1. La resolución deseada de la imagen no se conoce en el momento de escribir.
  2. El objeto de imagen necesita ser escalado a través de una matriz después de ser restaurado.
  3. Guardar en un mapa de bits de muy alta resolución es ineficiente en términos de memoria y tiempo de procesamiento.

¿Alguien sabe un trabajo que permite que las imágenes se escriben en el flujo sin causar este accidente?

Me hubiera agregado esto como un comentario, pero me falta la reputación …

El cambio de ruptura en Skia parece ser el cambio a SkImageRef_ashmem.cpp :

https://code.google.com/p/skia/source/detail?r=4980

El método de aplanamiento utilizado para comprobar un URI nulo y escribiría 0 en el flujo de salida si el uri era nulo. Pasar null a SkFlattenableWriteBuffer::writeString() da como resultado el bloqueo en strlen() .

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.