Android 4.3中引入了回归功能。过去在以前版本的Android中运行的代码现在会导致本机崩溃,从而关闭进程。
当将大于32 kb的图像绘制到由Picture
对象记录的画布时,会发生崩溃,该对象又通过writeToStream()
写入流。
当Skia试图写下一个字符串(我相信它是图像对象的Uri)时,崩溃正在发生。
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'按钮'按钮的布局。
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;
我知道Picture方法writeToStream()
和createFromStream()
已被弃用,但我不希望这会引入稳定性问题。
我需要写出Picture对象,因为我想将它从主应用程序传递给服务进程。由于以下原因,我无法在“将图片绘制成位图”的文档中使用推荐的解决方法:
是否有人知道可以将图像写入流而不会导致此崩溃的解决方法?
答案 0 :(得分:4)
我会将此作为评论添加,但我缺乏声誉......
Skia的突破性变化似乎是SkImageRef_ashmem.cpp
的变化:
https://code.google.com/p/skia/source/detail?r=4980
用于检查空URI的flatten方法,如果uri为null,则将0写入输出流。将null传递给SkFlattenableWriteBuffer::writeString()
会导致strlen()
中的崩溃。