修过的一个android framework原生系统代码bug

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/voidreturn/article/details/69388616

“坑”描述:

在对我们自己研发的一款android终端进行camera拍照压力测试时,发现当拍照张数达到几万张时,查看内存占用情况,发现内存泄露。

填“坑”:

frameworks/base/core/jni/android/graphics/YuvToJpegEncoder.cpp

bool YuvToJpegEncoder::encode(SkWStream* stream, void* inYuv, int width,
        int height, int* offsets, int jpegQuality) {
    jpeg_compress_struct    cinfo;
    skjpeg_error_mgr        sk_err;
    skjpeg_destination_mgr  sk_wstream(stream);

    cinfo.err = jpeg_std_error(&sk_err);
    sk_err.error_exit = skjpeg_error_exit;
    if (setjmp(sk_err.fJmpBuf)) {
        return false;
    }
    jpeg_create_compress(&cinfo);

    cinfo.dest = &sk_wstream;

    setJpegCompressStruct(&cinfo, width, height, jpegQuality);

    jpeg_start_compress(&cinfo, TRUE);

    compress(&cinfo, (uint8_t*) inYuv, offsets);

    jpeg_finish_compress(&cinfo);

    return true;
}

坑就在上面这个接口函数中:
熟悉libjpeg的同学会注意到,上面的接口在调用完jpeg_finish_compress()后,没有调用jpeg_destroy_compress(),这个接口是释放压缩工作过程中所申请的资源,主要就是jpeg压缩对象。
由于android原生接口中,没有调用jpeg_destroy_compress()导致每次泄露几十个字节,当拍照数量达到万级时,才会有所察觉。

怎么找到这个坑的:

这个过程后面有时间会详细写下,目前心得就是模块的架构十分重要,对这种数据流的控制,pipeline方式是比较好的方案,因为可以明确输入输出,然后通过伪造输入输出对各个模块进行单独的压力测试。最难控制的就是“洋葱”式的包裹调用,要像“剥洋葱”一样一层层的剥离十分麻烦。

你的android机上有这个问题吗:

9成的概率下你的手机应该不会有这个问题,因为上面我讲到是在我们做的一款终端上发现的问题,我们的终端芯片方案比较挫,没有硬编码模块,导致使用了android的软编码方案,也就用到libjpeg这个模块,也就触发了上面问题函数接口的调用。

牢骚:

做底层系统开发就是这样,一个bug耗费了很久的时间去测试,查找,验证。一层层剥离模块,逐步定位问题的大概位置,到最后精确定位问题,并解决,bug的解决可能就是一行代码的事(上面就加上destroy接口即可),但着实耗费了不少时间,如果按照代码行数计算kpi,这个performance应该是差的可以了。

上一篇:历时四年,给Google提交的Android Framework Bug终于被Fixed了


下一篇:闲扯工程师的版本管理概念