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()
.
- Skia y Android Pintar objetos de dibujo y su uso o documentación
- ¿Cómo encajan las piezas de la tubería de dibujo de Canvas de Android (2D)?
- Picasso no puede decodificar algunas imágenes: skia decode devuelto false
- Decodificador Skia no puede descodificar el flujo remoto
- Android Graphics Internals
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:
- La resolución deseada de la imagen no se conoce en el momento de escribir.
- El objeto de imagen necesita ser escalado a través de una matriz después de ser restaurado.
- 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?
- BitmapFactory.decodeStream devuelve siempre null y decodificador skia muestra decodificar devuelto falso
- Uso de Skia en Android NDK
- Cómo dibujar con una pintura "invertida" en Android Canvas?
- Dibujo de texto complejo en android ics en c nativo
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()
.