Android11 九宫格解锁流程
在我们分析完锁屏的一整个显示流程后,我们接着来分析一下上滑解锁的流程。
流程
首先,我们手指在锁屏界面上滑将会调用StatusBar中的onTrackingStopped方法
public void onTrackingStopped(boolean expand) {if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {if (!expand && !mKeyguardStateController.canDismissLockScreen()) {mStatusBarKeyguardViewManager.showBouncer(false /* scrimmed */);}}}
我们可以看到这里的代码有两项判断
1.判断是否处于锁屏界面
2.是否可以上滑以及有没有锁屏界面
接下来我们将要进入showBouncer方法,但实际上我们调用的就是KeyguardBouncer的show方法,所以
public void show(boolean resetSecuritySelection, boolean isScrimmed) {final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {// In split system user mode, we never unlock system user.return;}ensureView();mIsScrimmed = isScrimmed;// On the keyguard, we want to show the bouncer when the user drags up, but it's// not correct to end the falsing session. We still need to verify if those touches// are valid.// Later, at the end of the animation, when the bouncer is at the top of the screen,// onFullyShown() will be called and FalsingManager will stop recording touches.if (isScrimmed) {setExpansion(EXPANSION_VISIBLE);}if (resetSecuritySelection) {// showPrimarySecurityScreen() updates the current security method. This is needed in// case we are already showing and the current security method changed.showPrimarySecurityScreen();}if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {return;}final int activeUserId = KeyguardUpdateMonitor.getCurrentUser();final boolean isSystemUser =UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;// If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is// set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {return;}// This condition may indicate an error on Android, so log it.if (!allowDismissKeyguard) {Log.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);}mShowingSoon = true;// Split up the work over multiple frames.DejankUtils.removeCallbacks(mResetRunnable);if (mKeyguardStateController.isFaceAuthEnabled() && !needsFullscreenBouncer()&& !mKeyguardUpdateMonitor.userNeedsStrongAuth()&& !mKeyguardBypassController.getBypassEnabled()) {mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);} else {DejankUtils.postAfterTraversal(mShowRunnable);}mCallback.onBouncerVisiblityChanged(true /* shown */);mExpansionCallback.onStartingToShow();}
这个方法在上一篇文章中分析过了,那么用户解锁成功或者没有设置锁屏都将会调用dismiss方法
public boolean dismiss(boolean authenticated, int targetUserId,boolean bypassSecondaryLockScreen) {return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,bypassSecondaryLockScreen);}
今天我们不往锁屏完成后接下来的流程进行分析,我们来分析一下九宫格锁屏方式的解锁验证流程。
在我们上滑进入九宫格解锁的画面时,首先我们就会来到LockPatternView这个控件里面,去显示渲染整个画面,那么接下来我们就来分析一下它是如何来进行各种方法的判断的。
@Overridepublic boolean onTouchEvent(MotionEvent event) {if (!mInputEnabled || !isEnabled()) {return false;}switch(event.getAction()) {case MotionEvent.ACTION_DOWN:handleActionDown(event);return true;case MotionEvent.ACTION_UP:handleActionUp();return true;case MotionEvent.ACTION_MOVE:handleActionMove(event);return true;case MotionEvent.ACTION_CANCEL:if (mPatternInProgress) {setPatternInProgress(false);resetPattern();notifyPatternCleared();}if (PROFILE_DRAWING) {if (mDrawingProfilingStarted) {Debug.stopMethodTracing();mDrawingProfilingStarted = false;}}return true;}return false;}
这里是当用户进行绘制的时候会产生的几个状态,那么我们在这里依次分析一下他们的作用
handle消息传入 | 作用 |
---|---|
ACTION_DOWN | 触发触摸事件,根据坐标获取命中的点 |
ACTION_MOVE | 会遍历历史获取到的坐标,并且在网上查找资料发现还会进行局部区域的重绘 |
ACTION_UP | 当按下手势已经完成,接下来将会进行图案的验证 |
ACTION_CANCEL | 当前手势中止,将不会再进行现在正在进行的图案验证流程。但是这个事件不是因为自己中止,而是因为父控件对他进行了拦截而最终返回。 |
所以如果用户完成了绘制并且没有意外情况,接下来我们将会发送ACTION_UP消息,并调用handleActionUp()方法,于是我们会发现会回调函数mOnPatternListener.onPatternDetected(mPattern),这个mOnPatternListener是一个接口,我们可以找到在KeyguardPatternView里面有一个类实现了这个接口
private class UnlockPatternListener implements LockPatternView.OnPatternListener {//开始一个新的验证@Overridepublic void onPatternStart() {if (DEBUG) Log.d(TAG, "onPatternStart");mLockPatternView.removeCallbacks(mCancelPatternRunnable);/* UNISOC: Modify for Bug 1133395 {@ */if (mResumed) {mSecurityMessageDisplay.setMessage("");}/* @} */}//验证清空@Overridepublic void onPatternCleared() {}//添加一个拓展单元格(不明白)@Overridepublic void onPatternCellAdded(List<LockPatternView.Cell> pattern) {mCallback.userActivity();mCallback.onUserInput();}//检测是否匹配@Overridepublic void onPatternDetected(final List<LockPatternView.Cell> pattern) {if (DEBUG) Log.d(TAG, "onPatternDetected");//更新状态了解是否在锁屏的地方进行了尝试,不管有没有成功都将被记录//当解锁成功时候将会被清零mKeyguardUpdateMonitor.setCredentialAttempted();//禁用输入mLockPatternView.disableInput();if (mPendingLockCheck != null) {mPendingLockCheck.cancel(false);}//连接的点小于4个,直接作为无效密码,方法返回final int userId = KeyguardUpdateMonitor.getCurrentUser();if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {mLockPatternView.enableInput();onPatternChecked(userId, false, 0, false /* not valid - too short */);return;}if (LatencyTracker.isEnabled(mContext)) {//检查密码所需要的时间LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);//完全检查密码所需要的时间,也包括的解锁的操作LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);}//发布异步任务,检查锁屏的匹配//这里有四个参数,分别是是确定匹配程序、匹配传入的pattern,用户ID,回调函数mPendingLockCheck = LockPatternChecker.checkCredential(mLockPatternUtils,LockscreenCredential.createPattern(pattern),userId,new LockPatternChecker.OnCheckCallback() {//在检查之前@Overridepublic void onEarlyMatched() {if (DEBUG) Log.d(TAG, "onEarlyMatched");if (LatencyTracker.isEnabled(mContext)) {LatencyTracker.getInstance(mContext).onActionEnd(ACTION_CHECK_CREDENTIAL);}onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,true /* isValidPattern */);}//检查@Overridepublic void onChecked(boolean matched, int timeoutMs) {if (DEBUG) Log.d(TAG, "onChecked matched:" + matched);if (LatencyTracker.isEnabled(mContext)) {LatencyTracker.getInstance(mContext).onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);}mLockPatternView.enableInput();mPendingLockCheck = null;if (!matched) {onPatternChecked(userId, false /* matched */, timeoutMs,true /* isValidPattern */);}}//取消时@Overridepublic void onCancelled() {if (DEBUG) Log.d(TAG, "onCancelled");// We already got dismissed with the early matched callback, so we// cancelled the check. However, we still need to note down the latency.if (LatencyTracker.isEnabled(mContext)) {LatencyTracker.getInstance(mContext).onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);}}});if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {mCallback.userActivity();mCallback.onUserInput();}}
在确定解锁匹配时,会调用LockPatternChecker.checkCredential方法,返回一个AsyncTask进行启动,在doInBackground中调用checkCredential进行密码的验证,在这里
public boolean checkCredential(@NonNull LockscreenCredential credential, int userId,@Nullable CheckCredentialProgressCallback progressCallback)throws RequestThrottledException {throwIfCalledOnMainThread();try {VerifyCredentialResponse response = getLockSettings().checkCredential(credential, userId, wrapCallback(progressCallback));if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {return true;} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {throw new RequestThrottledException(response.getTimeout());} else {return false;}} catch (RemoteException re) {Log.e(TAG, "failed to check credential", re);return false;}}
原来的版本是把pattern使用patternToString算法转换成字符串,之后调用checkCredential进行验证
现在则是通过LockscreenCredential.createPattern去调用LockPatternUtils.patternToByteArray返回成一个字节数组
public static byte[] patternToByteArray(List<LockPatternView.Cell> pattern) {if (pattern == null) {return new byte[0];}final int patternSize = pattern.size();byte[] res = new byte[patternSize];for (int i = 0; i < patternSize; i++) {LockPatternView.Cell cell = pattern.get(i);res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');}return res;}
与此同时我们发现checkCredential中的if的response.getResponseCode都是在等于VerifyCredentialResponse的参数,OK和RETRY分别代表了通过以及重试(也就是失败了),这里提一下,失败次数过多会触发限制,在这里表现为抛出异常。
那么这个VerifyCredentialResponse是什么东西呢
首先我们根据代码,找到这个getLockSettings发现是一个外部调用的东西,它实际上就等于
ILockSettings service = ILockSettings.Stub.asInterface(
ServiceManager.getService(“lock_settings”));
这样一个服务,于是我们顺着去找,就找到android/frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsService.java
@Overridepublic VerifyCredentialResponse checkCredential(LockscreenCredential credential, int userId,ICheckCredentialProgressCallback progressCallback) {checkPasswordReadPermission(userId);try {return doVerifyCredential(credential, CHALLENGE_NONE, 0, userId, progressCallback);} finally {scheduleGc();}}
可以看到这里才是最终验证密码的地方
1.进行权限的验证
2.进行验证
3.垃圾清除的调度,释放内存
到这里整个流程就走完了,最底层密码验证的算法问题以后有机会再去分析
Android11 九宫格解锁流程相关推荐
- Android Mediatek bootloader oem锁定和解锁流程
目录 修改的文件: 文件修改说明: 这个修个是在mtk android11上的 , 就是个进入oem解锁流程 , 下面这部分代码就是开机检测按键 , 然后进入不同模式的.如果要修改其他的 也是大同小 ...
- android 九宫格解锁源码,Android 自己动手实现滑动九宫格解锁
Android 自己动手实现滑动九宫格解锁 文章主要以实现思路为主.来带领大家逐步实现该效果功能.如有问题,请多多提出 效果预览 整体思路分析 九宫格滑动解锁,为当下比较热门的手机,Pad等触屏设备很 ...
- android keyguard,Android8.1 SystemUI Keyguard之指纹解锁流程
手指在指纹传感器上摸一下就能解锁,Keyguard是怎么做到的呢? 下面我们就跟着源码,解析这整个过程. 何时开始监听指纹传感器? 先来看下IKeyguardService这个binder接口有哪些回 ...
- Android sim卡 pin码解锁流程.
sim卡 pin码解锁流程 1. PIN码解锁界面属于Phone Policy的一部分,代码位置在 \frameworks\base\policy\src\com\android\internal\p ...
- 第5章 SIM卡锁定PIN解锁流程
第5章 SIM卡锁定PIN解锁流程 1.插卡后,在卡初始化过程中,UiccController会从底层获取card状态,会知道要不要进行PIN校验,如果开启就暂停卡初始化流程,并弹出PIN输入框,输入 ...
- 指纹录入和指纹解锁流程
粗略了解下指纹的录入和解锁流程, 记录如下 Android P Finger Enroll: 1.Settings FingerprintEnrollIntroduction ...
- Android11 热点开启流程
Android11 热点开启流程 文章目录 Android11 热点开启流程 一.应用中热点开启和关闭的代码: 二.系统源码追踪 1.ConnectivityManager.startTetherin ...
- EFM32芯片jlink无法连接,无法调试,解锁流程
4.2.2 解锁 (1)按照前文硬件连接要求将JLink仿真器的调试接口与MCU系统调试接口进行连接.然后将仿真器连接到电脑USB端口上,并将EFM32LG230F128系统上电: (2)运行JLin ...
- 9宫格解锁 android_Android实现九宫格解锁
相信大家都有使用九宫格解锁,比如在设置手机安全项目中,可以使用九宫格解锁,提高安全性,以及在使用支付功能的时候,为了提高安全使用九宫锁,今天就为大家介绍Android实现九宫格的方法,分享给大家供大家 ...
最新文章
- 2021年中国AIoT产业全景图谱
- Swagger+AutoRest 生成web api客户端(.Net)
- 1010 Radix (25 分)【难度: 难 / 知识点: 二分查找】
- python的颜色有哪些_Python颜色分类及格式
- okhttp builder_从 OkHttp 到 Retrofit 到 OkHttps
- 高通侧目!联发科发布面向高端手机的5G芯片
- RocketMq学习笔记001---Kafka,ActiveMQ、RabbitMQ、RocketMQ消息中间件的对比
- css的white-space属性导致了空格问题——查看十六进制发现2020变成了c2a0
- python求立方尾不变_蓝桥杯—立方尾不变,有些数字的立方的末尾正好是该数字本身...
- 实验吧——Recursive
- 音频文件压缩大小如何操作?分享一个音频压缩的小技巧
- ShareTechnote系列LTE(10):多小区多RAT之间的交互
- 30岁张一鸣创业成功秘密武器,OKR“失控”管理法
- 腾讯与阿里巴巴投资可编程芯片公司Barefoot Networks
- H5微信授权登录 H5支付 外部浏览器微信支付 前端一个函数搞
- 数据湖和数据仓库的区别是什么?
- 分形图(fractal pictures)
- 第一个Java程序Hello World(IG牛逼)
- 在键盘上怎么点出来上下居中的点?
- C语言 信号集回调函数 避免子进程在信号回调注册完成之前全部结束
热门文章
- 全球及中国电子不停车收费系统(ETC)行业竞争模式及十四五建设现状分析报告2021-2027年
- shell脚本——循环语句
- Fall2018 学期规划(09/16修订)
- python 循环嵌套例子_Python循环嵌套案例-打印九九乘法表
- 魅族打开Android彩蛋,魅族 Flyme Android 10 首个内测版本已推送 强制开启 90Hz 彩蛋...
- 粤电博贺码头计算机管理系统中标,粤电博贺煤炭码头项目档案顺利通过省交通运输厅专项验收...
- Unity修改分辨率优化游戏性能
- 高并发核心编程Spring Cloud+Nginx秒杀实战,秒杀业务的参考实现
- 微信小程序 wx:for/if/elif/else等循环的写法以及wx.key的运用
- ubuntu 桌面卡死 解决方法