【填坑往事】Android手机锁屏人脸解锁优化过程实录
背景
写这篇文章,主要是为了以后面试方便。因为我简历上写了,上一份工作的最大亮点是将人脸解锁的速度由1200ms优化到了600ms,所以这些内容已经回答无数遍了。但每次总觉得回答的不完整,或者说总感觉可以发挥得更好,于是这里做一些简单的总结性的记录。
我2018年4月份进入到某手机公司,在其中工作了两年多的时间,这期间主要负责人脸解锁的功能。人脸解锁的速度优化,是入职开始的一个很重要的任务,前前后后持续了很长时间。做优化前,首先是明确目标,我接手时人脸解锁的速度是1200ms左右,而我们是参照的精品机Oppo、vivo、小米、华为等主流机型解锁速度大约在400~700ms不等,所以这也就成了我优化的目标。
整个人脸解锁的架构图如下所示:

优化的基本手段是将整个启动过程拆分为多个阶段,然后针对每一个阶段进行优化,优化流程逻辑或者采用更高效技术,归纳起来主要有如下这些步骤:
1、从按power键到SystemUI中的KeyguardService
优化前,使用的是广播方式,但我们知道使用广播方式来实现IPC性能是非常差的,速度很慢。优化后,采用AIDL取代广播方式,提升40ms左右。
有些面试官会问:为什么使用AIDL比使用广播速度更快?
网上没有搜到比较权威的答案,我自己整理了一下,我个人认为有如下几个原因:(1)广播的发送和接收过程中,有多次Binder实现的IPC。广播实现跨进程通信的方式也通过Binder实现的,这一点和AIDL一样。但是广播在注册时会将IntentFilter和Receiver信息通过Binder方式注册到AMS中,这里面会有很多封装、过滤等操作,将action,Receiver,Context、IntentFilter进行关联。发送者发送消息时会将action等信息封装到Intent中,然后通过Binder方式与AMS通信,将Intent等信息传入AMS中。AMS中经过匹配action,找到对应的注册者和接收者,然后再通过Binder方式和Receiver通信,这样就完成了一次广播的发送和接收,其中发生了多次Binder。而AIDL方式就过程就简单很多,直接在发送者和接收者之间一次Binder即可。广播是四大组件之一,在使用过程中会存在很多中间的处理过程,比如对Intent等的中间处理等。(2)广播有前台广播和后台广播之分,默认是后台广播。系统的内部存在无数的广播,由于系统资源有限,会优先处理一些非常重要的广播,这就使得默认情况下的广播会低优先级处理这些后台广播。同样也由于系统资源有限,所以不能随意将广播设置为前台广播。(3)根据注册的方式不同,广播有静态注册和动态注册的区分,如果是静态注册,就是并行广播,如果有多个地方注册了该广播,会根据注册的时间来依次处理广播事件。这一点不同于串行广播,动态注册是串行广播。
2、SystemUI与FaceId Service长期保持连接。
SystemUI与FaceId是通过AIDL来通信的, 优化前,SytemUI每次和FaceId通信完毕后都会断开连接,这样就导致在下次使用人脸解锁时,必须重新建立连接,会有一定程度的延迟。优化的方法就是让SystemUI和FaceId保持长久的连接。当然这一点缩短的时间并不太多。
3、使用Camera2 API代替Camera1 API
系统提供了Camera API-2,是官方对API-1的优化,性能更稳定,使用起来也更加方便。官方并没有明确说明使用API-2会比API-1更加快速,但实际开发中发现,使用API-2替换后,整个开启预览和开启相机的过程缩短了150ms左右。
4、提高相机帧率,尽量减少人脸解锁算法的等待时间
人脸解锁的核心流程是:SDK会预先录入使用者的人脸数据,在需要解锁时,相机通过摄像头以一定的帧率获取图像信息,通过API中的回调将图像信息传递给SDK。SDK中封装了人脸匹配算法,该算法会将相机传递的图像信息和预存的人脸数据进行匹配,并根据匹配结果返回对应的值,比如环境太黑、检测不到人脸、和预存的不是同一个人、匹配成功等各种匹配结果,都有一个数字与之对应。
SDK在匹配时,如果成功,一次匹配的时间大约是30ms,如果是失败的匹配,一次匹配大约50ms~100ms不等(在匹配过程中,如果有新的图像数据传递过来,会被过滤掉)。而平常使用时常常不能一次匹配成功,本次匹配失败后,很快从相机拿下一笔图像来匹配,直到在指定时间(设置的是5s)内匹配成功。为了能够让本次匹配失败后很快拿到下一笔图像,这就要求相机提高获取图像的帧率。这一点督促相机团队的同事,修改相机参数,综合考虑之下,取了15ms每帧的频率。
5、合理设置相机的初始曝光值
相机一般会默认设置一个曝光值,在不同环境中使用时,再根据周围环境来调整,以适应周围的光照环境。如果默认的曝光值设置不合适,会导致刚开启相机时,得到的前几笔图像要么太暗,要么太亮,需要自我调整达到一个高质量的状态。
在优化前,由于对默认的曝光值设置不合理,导致开启人脸解锁功能时,即便是很正常的光照环境下,面对正确的人脸时,前面多次匹配都因为图像质量太差,导致匹配失败。每次匹配失败都会浪费50~100ms的时间,这就导致每次解锁成功前,都会浪费300ms甚至更多的时间在相机自身调整曝光值上。
在后面做优化时,通过大量的测试和分析log,发现了每次匹配都不能一次成功的问题,然后将相机提供的数据转为图片,才发现图像的质量问题。后来和相机团队的同事,共同调试,得到一个比较合适的初始曝光值,解决了这个问题。
6、在启动人脸解锁时启动CPU拉频,并合理处理速度和省电之间的关系
人脸解锁算法执行是一个高密集计算的操作,为了提高解锁的速度,优化过程中采用了调度CPU最大核,并提高CPU频率的做法,使得匹配的速度有所提高。
调度CPU最大核并提高CPU频率,是一个非常耗电的过程。为了更好地平衡匹配速度和省电,这里又做了一个设计:人脸解锁超时时间设置的是5s,但实际上,如果周围环境正常,且是正确的人脸,大部分场景下都能在前1s内解锁完成,只有在环境异常或者非正确人脸的时候,才会在1s后还需要匹配,此种场景能解锁的概率就比较小了。所以这里的处理方法是,在人脸解锁的前1s调度CPU最大核,如果还没有解锁,则将CPU调回正常,而不是一直都使用CPU大核和高频。
7、合理使用并行代替串行
人脸匹配成功后,就可以立刻走解锁流程,并调用相机的关闭方法,而关闭相机需要150ms的时间。优化前原开发者采用的是串行的方式,也就是在人脸匹配完成后,在同一个线程中调用了关闭相机操作,相机关闭后才走锁屏界面消失的流程。这个优化点应该是很明显的,关闭相机的操作放在单独的一个线程去执行就可以了,这样一来就能够再优化150ms的时间。至于原开发者为什么要采用串行,不得而知。
当然,优化过程还有其他很多的细节,比如一些流程的时间复杂度优化,非必要流程的精简,要求sdk人脸匹配算法做优化,新手机中使用了性能更好的CPU、相机硬件等。
【填坑往事】Android手机锁屏人脸解锁优化过程实录的更多相关文章
- iOS开发之应用内检测手机锁屏,解锁状态
iPhone的锁屏监测分为两种方式监听: 1. 程序在前台,这种比较简单.直接使用Darwin层的通知就可以了: #import <notify.h> #define Notificati ...
- Android忘记锁屏密码如何进入手机?
Android忘记锁屏密码如何进入手机? 1.关闭手机 2.进入recovery模式(即恢复模式,记住不是挖煤模式.进入恢复模式不同手机有不同方法,三星的话安主页键,关机键和音量+(或-键), ...
- Android逆向之旅---Android中锁屏密码算法解析以及破解方案
一.前言 最近玩王者荣耀,下载了一个辅助样本,结果被锁机了,当然破解它很简单,这个后面会详细分析这个样本,但是因为这个样本引发出的欲望就是解析Android中锁屏密码算法,然后用一种高效的方式制作锁机 ...
- 手机锁屏js倒计时停止问题解决办法探索
如图,有这么个需求,测试人员在测试过程中提了一个bug,手机锁屏再唤醒倒计时时间没有更新,仍从锁屏的时间继续,于是开始寻找解决之法 经了解得知,锁屏时候,浏览器的一切活动会停止运行,那么js也无法幸免 ...
- Android一键锁屏源码
APK下载 源程序下载 锁屏流程如下(参考于Android一键锁屏开发全过程[源码][附图]) 源码参考于一键锁屏 源码 一共有2个Java文件: package com.example.onekey ...
- BroadcastReceiver之实现锁屏、解锁样例
好久没有写android的小样例了,因为前几天写了一篇关于Intent.Action的文章(http://blog.csdn.net/ljphhj/article/details/38796739). ...
- 在iOS上增加手势锁屏、解锁功能
在iOS上增加手势锁屏.解锁功能 在一些涉及个人隐私的场景下,尤其是当移动设备包含太多私密信息时,为用户的安全考虑是有必要的. 桌面版的QQ在很多年前就考虑到用户离开电脑后隐私泄露的危险,提供了“离开 ...
- TTY锁屏与解锁
今天在tmux中使用vim时,不小心按了CTRL+S,结果整个vim不能使用了,在网上查到这里会有锁屏的问题,具体如下: 在tmux中,按CTRL+S,锁屏,按CTRL+Q,解锁.与系统的锁屏和解锁是 ...
- Android 监听手机锁屏的工具类
自定义 ScreenListener package com.example.teagardenhd.Listener; import android.content.BroadcastReceive ...
随机推荐
- 【题解】NOIP2018 旅行
题目戳我 \(\text{Solution:}\) 首先题目描述有一点不准确:回头是必须要走完一条路无路可走的时候才能返回. 对于树的情况:显然贪心做就完事了. 对于基环树的情况:对于一个\(n\)条 ...
- 【题解】[USACO09NOV]A Coin Game S
Link \(\text{Solution:}\) 菜鸡自己想出来了状态设计,但是没有实现出来--菜死了 设\(dp[i][j]\)表示该选第\(i\)个,最多选\(j\)个的最优解.注意这里的定义仅 ...
- selenium3+python3自动化环境搭建
(我也是小白,刚开始接触自动化,以下内容是我自己在配置环境的时候遇到的问题及解决方法,是后面才记录的要是有什么遗漏或者问题,欢迎帮忙指出来.)1.1首先下载python下载网址:https://www ...
- shiro入门学习--授权(Authorization)|筑基初期
写在前面 经过前面的学习,我们了解了shiro中的认证流程,并且学会了如何通过自定义Realm实现应用程序的用户认证.在这篇文章当中,我们将学习shiro中的授权流程. 授权概述 这里的授权指的是授予 ...
- Dockerize ASP。净样板项目
Get the source code from the Github repository. 介绍 在这篇文章中,我将一步步地向你展示如何在Docker上运行ABP模块零核心模板.然后,我们将讨论其 ...
- Springboot应用使用Docker部署
首先准备好springboot应用,然后打包,我这里已经准备好了一个jar包 然后上传到服务器,准备一个目录用于存放jar包和Dokerfile文件 编写Dokerfile文件 我这里写的很简单,就简 ...
- Varnish 6.2.2 的介绍与安装
一.简介 Varnish 是一款高性能且开源的反向代理服务器和 HTTP 加速器,其采用全新的软件体系机构,和现在的硬件体系紧密配合,与传统的 Squid 相比,Varnish 具有性能更高.速度更快 ...
- 网站搭建-云服务器ECS-镜像管理
学习笔记: 快照,系统盘可创建镜像,数据盘不可以. 实例可以直接创建镜像,包括系统盘和数据盘 复制镜像: 新购服务器,选择镜像(又买). 共享镜像: 账号ID就是UID 云市场获取镜像; 1. 创建新 ...
- 数组的高级应用含ES6 for of 用法
// 在ES5中常用的10种数组遍历方法: // 1. 原始的for循环语句 // 2. Array.prototype.forEach数组对象内置方法 // 3. Array.prototype.m ...
- 为什么堆化 heapify() 只用 O(n) 就做到了?
heapify() 前面两篇文章介绍了什么是堆以及堆的两个基本操作,但其实呢,堆还有一个大名鼎鼎的非常重要的操作,就是 heapify() 了,它是一个很神奇的操作, 可以用 O(n) 的时间把一个乱 ...