历时四年,给Google提交的Android Framework Bug终于被Fixed了
历时四年,Google终于修复了一个我发现的Android Framework Bug
2014年在做一个Android终端设备开发过程中,发现了一个Android Framework层的Bug,给Google提交了issue和解决方案,和外界传言一致Google一般不太在意个人开发者提交的issue,直到2017年12月,再次提交了issue,在几轮沟通无果下,忍不住喷了Google几句后,终于该issue被转交给了Android development team处理,又经过快三个月的时间收到了下面的答复:
google issues:https://issuetracker.google.com/issues/70016687
issue背景:
在对我们自己研发的一款Android终端设备进行Camera拍照压力测试时,发现当拍照张数达到数万张时,出现OOM,导致系统崩溃。
issue分析解决过程:
该项目为开发一款Android工业终端设备,采用TI芯片方案,由于芯片方案商支持不够完善(主要TI被高通打的放弃了移动端芯片市场),Camera的HAL层需要我们自己移植适配。
分析思路:
首先看下Android系统架构图中中Camera功能模块的分布情况,从App层->Framework->HAL->Kernel一路下来:
(图片取自https://blog.csdn.net/asd1031/article/details/53699867)
- 首先怀疑测试app自身存在内存问题。
- Android application Framework,libraries层和jni相关模块是经过Google大量验证的模块,出现问题的概率比较小,暂时排除。
- 怀疑HAL层移植问题。
怀疑1:测试app问题
压力测试app由测试同学开发提供的,该app每隔3s触发一次拍照操作,并对拍摄的照片进行清理,以达到拍摄10万张照片的测试目的。基于以上分析,为了排除测试app问题,采用Android原生Camera app进行压力测试,编写monkey测试脚本,触发原生Camera app拍照,进行压力测试。(此处遇到的问题是:如何实现对照片的清理工作,直接触发shell环境下rm操作,并不会清除Android内部文件缓存索引,拍摄几千张照片后仍然会导致存储空间用尽,解决此问题也耗费了点时间,不过不是本文的重点,此处不做展开)
结果:通过原生Camera app进行测试后,仍然出现内存泄漏,此处基本排除测试app的问题。
怀疑2:HAl层
基于之前的分析,我们把怀疑对象聚集在我们自己集成的Android HAL层,在分析之前,简单描述下Android Camera拍照的流程:Linux Kernel提供标准的v4l2接口,供上层(此处即为HAL)获取图像原始数据,HAL层拿到图像数据进行编码(一般为jpeg),回调给Camera service。其中Linux Kernel下Camera驱动和HAL适配层一般由芯片厂商提供,其余部分由Linux Kernel和Android系统官方维护,开发。
这样对HAL的测试分为三步:
- 验证芯片厂商的Camera驱动是否存在问题。
- 验证HAL层图像数据捕获流程是否存在问题。
- 验证图像编码流程是否存在问题。
Camera驱动
Android系统是基于Linux Kernel开发,支持标准的v4l2接口,只需要编写一个简单的基于v4l2的视频捕获程序就可以验证camera驱动的问题,此处测试验证没有内存泄漏,排查驱动问题。
HAL层视频捕获流程
测试思路非常明确,难点在于要把芯片提供商的HAL层源码中进行视频捕获功能的模块剥离出来,单独进行压力测试。(由于原厂提供的HAL层代码,耦合比较严重,在不影响内部流程,结构的情况下,要找到适合的切面mock一些数据接口,才好进行有效的测试。)
经过以上的工作,进行了压力测试,系统未出现内存泄漏,基本排除HAL层捕获流程。
HAL层图像编码流程
继续对图像编码部分剥离,进行压力测试,发现内存泄漏,基本定位大概的泄漏位置,不过由于Android整个编码过程也进行层层的封装,泄漏位置还需要继续细致的定位,这样经过层层的细化,像剥洋葱一样一层层mock输入数据,最终定位在Android系统层的jpeg编码处理中:(frameworks/base/core/jni/android/graphics/YuvToJpegEncoder.cpp)
关于Android的jpeg编码:Android系统jpeg编码支持硬编码和软编码,如果芯片集成了jpeg硬件编码模块,会优先选择硬编码,而如果没有该模块,会采用软件的jpeg编码进行处理。
Android采用的软件编码库是业内知名的libjpeg库,而正是对这个库的使用出了问题:
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(),这个接口是释放压缩工作过程中所申请的资源,就是代码中的cinfo结构,该结构只占十几个字节的内存, 这样就导致了每拍摄一张照片,就泄漏一个cinfo的内存,当拍照数量达到万级时,才会有所察觉。
对这种数据流的控制,pipeline方式是比较好的方案,因为可以明确输入输出,这样非常方便通过伪造输入数据对各个模块进行单独的压力测试,最难控制的就是“洋葱”式的包裹调用,要像“剥洋葱”一样一层层的剥离,找准切面十分麻烦。
这个bug是否影响到你的Android手机
七成的概率下你的手机应该不会有这个问题,即时有这个问题你也很难发现这个问题,因为上面讲到android系统有两种编码方式选择,优先使用硬件编码模块,如果没有硬件编码模块,才会使用软编码的方式,而目前大部分中高端的芯片方案都集成了硬件模块,只有在少数低端芯片上才会使用软编码的方式,并且即使你的手机没有硬编码模块,用的软编码,也很难遇见这个问题,因为对于普通用户,持续拍摄上万张照片是不太可能的,第一受限于手机的存储空间(一万张照片,至少要30G的空间),第二即使能拍摄上万张照片,但要保持手机一直工作不重启也还是比较苦难的(总会死个机啥的)。
哈哈,这么一说发现这个bug其实是一个不会发生的bug了!!!不过我们之前的产品,定位于工业级别,对图像采集有比较高的要求,所以制定了10万张照片的测试标准,也就让我发现了这个不会影响到大部分人的bug。
最后再吐槽下Google
改bug我在2014年就已经提交了issue,不过没持续关注,过了几个月被莫名其妙的关闭了,当时没有在意,不过当Android 6.0,7.0版本出来时,我都看了下这个bug,一直存在,所以在去年(2017年)12月份又提了一个issue,Google方面的处理人仍然各种推诿扯皮,最后我没忍住喷了几句,这次Google方面回复会转给开发团队处理,终于在今年(2018年)给出了fixed的结论。
历时四年,给Google提交的Android Framework Bug终于被Fixed了相关推荐
- 初识Android framework层
Android系统的构成如下,从上到下依次是 Application应用层 Framework框架层 LIbrary系统库层 Linux内核层 关于Framework层: Android的Framew ...
- 金三银四的面试黄金季节,Android面试题来了!
金三银四的跳槽季节,你准摆好了吗? 首先我们分享一个Android知识图谱. 下面是一些面试官基本必问的问题,请一定要去了解! 基础知识 – 四大组件(生命周期,使用场景,如何启动) java基础 – ...
- 一、初识GVR ---- Android VR视频/Google VR for Android /VR Pano/VR Video
原文链接: http://blog.csdn.net/qq_24889075/article/details/52118633 http://www.jianshu.com/p/09c0822b9d1 ...
- 一起看 I/O | Google TV 和 Android TV OS 的最新进展
在接触到的娱乐内容与日俱增的今天,有研究表明,三分之一的美国家庭现每周的电视观看时长在 25 个小时以上.随着电视体验的不断演进,我们也为自己设定了一个目标,那就是为用户打造量身定做的电视使用体验,让 ...
- Google OAuth2 for Android(type of web OAuth)
Google OAuth2 for Android(type of web OAuth) 一.应用创建和注册 1.登录google 登录Google 应用 2.创建项目 3.创建OAuth同意屏幕 4 ...
- Android的BUG(四) - Android app的卡死问题
做android,免不了要去运行一些跑分程序,常用的跑分程序有quadrant(象限),nbench,安兔兔等.作为系统工程师,对这些跑分 程序都非常的不屑,这个只能是一个不客观的参考,但客户都喜欢拿 ...
- RecyclerView(四)设置分割线样式(Android 5.0 新特性)
Android RecyclerView(四)设置分割线样式(Android 5.0 新特性) 样式一 在这里,其实是设置了每一个 条目布局中的子布局的android:layout_margin = ...
- Google+ 团队的 Android UI 测试
https://github.com/bboyfeiyu/android-tech-frontier/tree/master/android-blog/Google%2B%20%E5%9B%A2%E9 ...
- 【多图】Google工程师解析Android系统架构--what is android(转载)
导读:Sans Serif是Google的一位工程师,近日发布了一篇博文非常清楚的描述了Android系统架构,中国移动通信研究院院长黄晓庆在新浪微博上推荐了该文,并认为文中对Android的介绍很好 ...
最新文章
- 微信新版支持读取iPhone M7/M8协处理器运动数据 与好友PK一下运动量吧
- 谷歌、阿里们的杀手锏:3大领域,10大深度学习CTR模型演化图谱(附论文)
- 《精通Wireshark》—第2章2.6节总结
- 有重叠与无重叠序列之序列检测与序列产生
- 绝地求闪退be服务器未运行,绝地求生大逃杀BE启动失败,应用程序无法正常启动...
- 分享我第一次做项目的感受
- mysql官网 ab_MySQLAB同步
- JWTToken超时刷新策略
- 如何使用Docker在GitLab上设置CI
- React系列---Babel
- 微信小程序调试之【不在以下合法域名列表中】
- 2014校招 百度试题及答案
- php 调用cron jobs,在CentOS 6.4中使用CronJobs执行PHP不起作用?
- EJB的beans们
- Mac 安装 Grunt
- Atitit pdf转文本 pdf2txt v4 t83.docx Atitit pdf转文本 pdfutil 目录 1.1. Pdfbox cmd 模式 TextToPDF	1 1.2. Pdf
- python继承list_python中 class和l
- 不到90天的时间,备考数据库系统工程师还来得及吗?
- python读取组合惯导数据,并进行坐标转换到北东天、utm坐标系
- 交互设计——超越人机交互