In Android 4.3, regression was introduced. Code that used to work in previous versions of Android now causes its own crash, which terminates the process.
A crash occurs when drawing an image larger than 32 kb into the canvas, which is recorded by the Picture object, which, in turn, is written to the stream through writeToStream() .
Skia crashes when trying to write a string (which I believe is the Uri of the image object).
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)
The following program shows how to reproduce this problem. All that is needed is a layout with a button that has the identifier 'button'.
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() {
The two lines setting BitmapFactory.Options are needed to get the Skia anti-aliasing code to write image data (otherwise the images are emitted).
options.inInputShareable = true; options.inPurgeable = true;
I am aware that the Picture writeToStream() and createFromStream() methods are deprecated, but I did not expect this to cause a stability problem.
I need to write a Picture object as I want to transfer it from the main application to the service process. I cannot use the recommended workaround in the documentation that says “draw image into bitmap” for the following reasons:
- The desired image resolution is unknown during recording.
- The Picture object must be scaled using the matrix after restoration.
- Saving to a very high resolution bitmap is inefficient in terms of memory and processing time.
Does anyone know a job that allows you to write images to a stream without causing this failure?