【面试】工作中遇到的难点及解决方案——人脸解锁相机冲突问题
写这篇文章,主要也是为了方便面试。因为最近两年的工作主要都是人脸解锁,面试官问得比较多的一个问题是,工作当中遇到印象最深的难点问题是什么,以及是如何解决的。最近两年中印象最深刻的一个难点问题是:人脸解锁相机冲突问题。
1、现象描述
相机冲突的问题的触发场景是:当前正在使用相机应用,比如“扫一扫”、“拍照”等,快速按power键熄屏然后亮屏,触发人脸解锁功能,然后人脸解锁完成并返回到熄屏前的相机应用界面。出现相机冲突的概率和按power键的速度有关,在解决这个问题前,这种相机冲突现象几乎是必现,现象是相机应用界面卡死、黑屏、crash或者提示没有权限等。
2、原因分析
人脸解锁具有对相机资源使用的最高权限(这一点由相机驱动/框架层设置的),表现在两个方面:
(1)当有其它应用正在使用相机资源时,如果启动了人脸解锁,那么人脸解锁会抢过相机资源。
(2)当人脸解锁完毕后,需要一些时间去释放相机(比如150ms),这期间如果有其它应用要使用相机资源,则会申请失败。
这两个场景都会产生相机冲突,相应的现象是:
(1)人脸解锁抢了其它应用的相机资源,会导致其它应用异常,根据这些应用处理方式不同,现象也各有差异,有的直接crash,有的黑屏,有的卡在图像界面。
(2)如果是后一种场景,人脸解锁还没有释放相机资源,而其它应用又要申请,这时候其它应用基本上都会弹出对话框,提示“没有相机权限”或者“相机被其它应用占用”等类似的提示。
3、第一版解决方案
既然找到了如上两种相机冲突的原因,那么就可以对症下药,当时通过白名单的方式出了一版解决方案。具体的做法是:
(1)针对第一个原因,在启动人脸解锁时占用相机资源前,等待一定的时间,让其它应用主动释放掉相机资源后,再继续申请相机,走人脸解锁流程。通过自测发现,当前正在使用“扫一扫”等相机应用,熄屏时该应用会主动释放掉相机资源,但不同应用的相机功能释放的时间不同,有的需要100ms,有的需要150ms,有的需要200ms等。
所以解决办法是:在代码中列一个白名单,记录下不同相机应用所在组件的路径,比如“com.android.camera.CameraActivity”(可以通过adb命令等方式获取),然后通过测试找到该应用释放相机的时间且记录下来。这样,当亮屏时,通过白名单来确定需要延迟启动人脸解锁的时间,比如:熄屏前正在使用“美团”的“扫一扫”,我在白名单中查到了“美团”的“扫一扫”所在组件的路径,且确定其释放相机需要100ms,那么按power键亮屏后,我就先等待100ms,给“美团”足够的时间主动释放相机,然后再启动人脸解锁流程。这样就避免了人脸解锁暴力抢占其它应用相机资源这种场景了。
(2)针对第二个原因,通过测试发现人脸解锁自己释放相机需要150ms的时间,所以当得知灭屏前使用的是相机类应用时(和上一原因采用白名单方式一样),人脸解锁完成后等待150ms后再让锁屏消失,返回到灭屏前的相机应用界面。此时该相机应用会重新申请相机,且人脸解锁已经释放完相机了,所以就不存在相机被占用的尝场景了。
4、第二版优化方案
第一版方案确实解决了相机冲突的问题,但是也有一些很明显的弊端:
(1)碰到正在使用相机类应用时,人脸解锁时间变长了,因为人脸解锁前后都需要等待不少时间。这其中有些时间是不一定需要等待的,我们设置的等待时间是考虑的最坏的情况,比如亮屏时很有可能前面的相机资源已经释放了,或者已经释放一部分了,不需要再等待200ms这么长时间才去启动人脸解锁。
(2)难以维护。经常使用的相机类应用太多了,即便只算上经常时用的,也有几十款之多,需要将这些组件路径都保存在白名单中。而且有些应用改版升级,原有的路径可能会有改动,那么又得把新的路径加入到白名单。同时由于软硬件的升级,这些应用原本释放相机资源的时间缩短了。
针对这些问题,又做了进一步的优化:
(1)调用框架提供的接口,实时判断相机是否可用,并监听相机的状态。当亮屏时,如果此时相机资源是空闲的,那就直接调用人脸解锁。如果发现相机正被其它应用给占了,但还没有释放掉,那就等待。直到监听到相机资源被释放了(框架提供的回调方法),就立刻继续走人脸解锁流程。这样就避免了方案一中可能不必要的等待。这个方法其实很容易想到,但是最初相机团队同事明确说明没有实时监听相机状态的接口可以用,且最初需要解决冲突的场景不多,所以就采用了白名单方案。
(2)人脸解锁完成后,通过相机框架/驱动团队同事的配合,动态降低人脸解锁占用相机的权限。这样就无需等待150ms来保证人脸解锁释放相机了,解锁完直接返回到其它应用的相机,这些应用可以直接抢过人脸解锁的相机资源。这个方案需要框架团队、相机驱动团队联调,且需要改动的地方比较多,所以刚开始是被否定的。