2、相机启动延迟分析:冷启动 vs 热启动、Activity启动流程、CameraService初始化、HAL设备打开流程、Sensor上电时序
相机启动延迟,说白了就是用户按下相机图标到取景画面出现之间的那段时间。这个时间长短直接影响用户的第一印象。我做过不少项目,客户反馈最多的就是「怎么这么慢?」——嗯,今天我们就来拆解这个延迟到底从哪来的。
2.1 冷启动 vs 热启动:差别在哪?
先搞清楚两个概念。冷启动,指的是相机进程完全不存在,需要从头创建。热启动,则是相机进程已经在后台存活,只是界面被回收了。
| 对比项 | 冷启动 | 热启动 |
|---|---|---|
| 进程状态 | 不存在,需fork | 后台存活 |
| 典型耗时 | 800ms - 1500ms | 200ms - 500ms |
| 主要瓶颈 | 进程创建 + 服务初始化 | 界面重建 + Surface重连 |
| 用户感知 | 明显等待 | 几乎无感 |
我在项目中遇到过一种情况:某款手机冷启动要2秒多,但热启动只要300ms。用户投诉说「相机太慢」,其实他们指的是冷启动。所以优化时,冷启动才是硬骨头。
核心观点:冷启动优化是相机性能的「面子工程」。热启动再快,冷启动慢一样被骂。
2.2 Activity启动流程:从点击到onCreate
用户点击相机图标,系统会做什么?我画了一张图,你看完就明白了。
你想想看,从点击到onCreate,中间经历了什么?AMS要查Intent、要判断进程是否存在、要fork进程(冷启动时)、要加载Application类。这些全是耗时的。
优化小技巧:Application.onCreate里不要做耗时操作。我见过有人在里面初始化图片加载库、数据库、网络库……结果相机启动硬生生多了200ms。把这些东西延迟加载,或者放到子线程去。
2.3 CameraService初始化:服务端在忙什么
Camera.open()调用后,客户端会通过Binder跟CameraService通信。CameraService要做什么?
- 加载HAL库——通过dlopen加载camera.provider@2.x.so
- 枚举摄像头——调用HAL的getCameraIdList
- 创建设备会话——openCameraDevice
- 配置流——configureStreams
这里有个坑。我记得有一次,某个平台的HAL库加载花了300ms,原因是so库依赖了太多其他库,导致dlopen时递归加载。后来我们把不必要的依赖去掉,加载时间降到了50ms以内。
注意:CameraService初始化是串行的。如果系统同时有多个相机应用在请求,后面的请求会被阻塞。所以,不要频繁open/close相机。
2.4 HAL设备打开流程:从HAL到Kernel
HAL层打开设备,说白了就是调用open()方法,然后底层驱动开始干活。流程大致如下:
// HAL层调用链
camera_device_t->open()
└─> vendor_module_open()
└─> sensor_open()
└─> v4l2_open("/dev/videoX")
└─> kernel driver probe()
└─> power on sensor
└─> i2c通信初始化
└─> mclk配置
└─> gpio拉高
这个过程中,最耗时的往往是sensor上电和初始化。我见过一个项目,sensor上电要等100ms,因为驱动里加了不必要的延时。后来我们查datasheet,发现其实50ms就够了。
2.5 Sensor上电时序:为什么这么慢?
Sensor上电不是简单地把电供上就行。它有一套严格的时序要求:
| 步骤 | 操作 | 典型耗时 | 说明 |
|---|---|---|---|
| 1 | 拉高AVDD(模拟电压) | 1ms | 需要稳定到目标电压 |
| 2 | 拉高DVDD(数字电压) | 1ms | 需在AVDD之后 |
| 3 | 拉高IOVDD(IO电压) | 1ms | 最后上电 |
| 4 | 提供MCLK(主时钟) | 2ms | 时钟稳定时间 |
| 5 | 拉高Reset引脚 | 1ms | 释放复位 |
| 6 | 等待Tdelay | 10-50ms | sensor内部初始化 |
| 7 | I2C写入初始化序列 | 5-20ms | 配置寄存器 |
你看,光上电时序就要20-80ms。这还没算后面的I2C配置。我曾经优化过一个项目,把Tdelay从50ms砍到20ms,因为看了datasheet发现那个延时是给老款sensor用的,新款根本不需要那么久。
关键点:Sensor上电时序的优化空间很大。很多驱动工程师习惯「照搬参考代码」,但参考代码往往留了余量。你完全可以去读datasheet,把不必要的延时去掉。
2.6 整体延迟分布:谁才是罪魁祸首?
我整理了一份典型的冷启动延迟分布数据,你看看:
| 阶段 | 耗时(ms) | 占比 | 优化难度 |
|---|---|---|---|
| Activity启动(进程创建+onCreate) | 300-500 | 30% | 中 |
| CameraService初始化 | 100-200 | 15% | 低 |
| HAL设备打开 | 100-300 | 20% | 中 |
| Sensor上电+初始化 | 100-300 | 20% | 高 |
| Preview启动(Surface+Stream) | 100-200 | 15% | 低 |
看到没?Activity启动和Sensor初始化占了半壁江山。所以优化时,优先盯着这两块。
我的建议:拿到一个新平台,先做一次完整的启动trace。用Systrace或者Perfetto抓一下,看看每个阶段花了多少时间。别凭感觉优化,数据说话。
嗯,关于相机启动延迟的分析就到这里。核心思路是:先分清楚冷热启动,再逐段拆解Activity、CameraService、HAL、Sensor这几个环节。每个环节都有优化空间,但你要知道瓶颈在哪,才能对症下药。
公众号:蓝海资料掘金营,微信deep3321