调用 Picture.writeToStream() 时 Android 4.3 中的本机崩溃

Posted

技术标签:

【中文标题】调用 Picture.writeToStream() 时 Android 4.3 中的本机崩溃【英文标题】:Native Crash in Android 4.3 when calling Picture.writeToStream() 【发布时间】:2013-07-30 15:15:15 【问题描述】:

android 4.3 中引入了回归。以前在 Android 早期版本中运行的代码现在会导致本机崩溃,从而关闭进程。

将大于 32 kb 的图像绘制到画布中时会发生崩溃,该画布由 Picture 对象记录,该对象又通过 writeToStream() 写入流。

当试图写掉一个字符串(我相信这是图像对象的 Uri)时,Skia 发生了崩溃。

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)

以下程序显示了如何重现此问题。所需要的只是一个带有 id 为“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() 
                        // 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();
            
        );
    

需要设置 BitmapFactory.Options 的两行来获取 Skia 展平代码以写出图像数据(否则会发出图像)。

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

我知道图片方法 writeToStream()createFromStream() 已被弃用,但我不认为这会引入稳定性问题。

我需要写掉 Picture 对象,因为我想将它从主应用程序传递到服务进程。由于以下原因,我无法使用文档中建议的“将图片绘制为位图”的解决方法:

    在撰写本文时,还不知道图片的所需分辨率。 图片对象恢复后需要通过矩阵放大。 保存到非常高分辨率的位图在内存和处理时间方面效率低下。

有没有人知道一种可以将图像写入流而不会导致崩溃的解决方法?

【问题讨论】:

【参考方案1】:

我会将此添加为评论,但我缺乏声誉......

Skia 中的重大变化似乎是对 SkImageRef_ashmem.cpp 的更改:

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

用于检查空 URI 的 flatten 方法,如果 uri 为空,则将 0 写入输出流。将 null 传递给 SkFlattenableWriteBuffer::writeString() 会导致 strlen() 崩溃。

【讨论】:

已作为问题 1457 报告给 Skia 项目:code.google.com/p/skia/issues/detail?id=1457 这应该在未来的 Android 版本中得到修复,因为核心 Skia 团队已经检查了修复,请参阅 code.google.com/p/android/issues/detail?id=58257

以上是关于调用 Picture.writeToStream() 时 Android 4.3 中的本机崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Java中方法调用总结

系统调用与函数调用

java三种调用方式(同步调用/回调/异步调用)

LINUX系统调用

引用调用 vs 复制调用调用

RPC 调用和 HTTP 调用的区别