在我们分析完锁屏的一整个显示流程后,我们接着来分析一下上滑解锁的流程。

流程

首先,我们手指在锁屏界面上滑将会调用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 九宫格解锁流程相关推荐

  1. Android Mediatek bootloader oem锁定和解锁流程

    目录 修改的文件: 文件修改说明: 这个修个是在mtk android11上的 , 就是个进入oem解锁流程  , 下面这部分代码就是开机检测按键 , 然后进入不同模式的.如果要修改其他的 也是大同小 ...

  2. android 九宫格解锁源码,Android 自己动手实现滑动九宫格解锁

    Android 自己动手实现滑动九宫格解锁 文章主要以实现思路为主.来带领大家逐步实现该效果功能.如有问题,请多多提出 效果预览 整体思路分析 九宫格滑动解锁,为当下比较热门的手机,Pad等触屏设备很 ...

  3. android keyguard,Android8.1 SystemUI Keyguard之指纹解锁流程

    手指在指纹传感器上摸一下就能解锁,Keyguard是怎么做到的呢? 下面我们就跟着源码,解析这整个过程. 何时开始监听指纹传感器? 先来看下IKeyguardService这个binder接口有哪些回 ...

  4. Android sim卡 pin码解锁流程.

    sim卡 pin码解锁流程 1. PIN码解锁界面属于Phone Policy的一部分,代码位置在 \frameworks\base\policy\src\com\android\internal\p ...

  5. 第5章 SIM卡锁定PIN解锁流程

    第5章 SIM卡锁定PIN解锁流程 1.插卡后,在卡初始化过程中,UiccController会从底层获取card状态,会知道要不要进行PIN校验,如果开启就暂停卡初始化流程,并弹出PIN输入框,输入 ...

  6. 指纹录入和指纹解锁流程

    粗略了解下指纹的录入和解锁流程, 记录如下 Android P Finger Enroll:     1.Settings         FingerprintEnrollIntroduction ...

  7. Android11 热点开启流程

    Android11 热点开启流程 文章目录 Android11 热点开启流程 一.应用中热点开启和关闭的代码: 二.系统源码追踪 1.ConnectivityManager.startTetherin ...

  8. EFM32芯片jlink无法连接,无法调试,解锁流程

    4.2.2 解锁 (1)按照前文硬件连接要求将JLink仿真器的调试接口与MCU系统调试接口进行连接.然后将仿真器连接到电脑USB端口上,并将EFM32LG230F128系统上电: (2)运行JLin ...

  9. 9宫格解锁 android_Android实现九宫格解锁

    相信大家都有使用九宫格解锁,比如在设置手机安全项目中,可以使用九宫格解锁,提高安全性,以及在使用支付功能的时候,为了提高安全使用九宫锁,今天就为大家介绍Android实现九宫格的方法,分享给大家供大家 ...

最新文章

  1. 2021年中国AIoT产业全景图谱
  2. Swagger+AutoRest 生成web api客户端(.Net)
  3. 1010 Radix (25 分)【难度: 难 / 知识点: 二分查找】
  4. python的颜色有哪些_Python颜色分类及格式
  5. okhttp builder_从 OkHttp 到 Retrofit 到 OkHttps
  6. 高通侧目!联发科发布面向高端手机的5G芯片
  7. RocketMq学习笔记001---Kafka,ActiveMQ、RabbitMQ、RocketMQ消息中间件的对比
  8. css的white-space属性导致了空格问题——查看十六进制发现2020变成了c2a0
  9. python求立方尾不变_蓝桥杯—立方尾不变,有些数字的立方的末尾正好是该数字本身...
  10. 实验吧——Recursive
  11. 音频文件压缩大小如何操作?分享一个音频压缩的小技巧
  12. ShareTechnote系列LTE(10):多小区多RAT之间的交互
  13. 30岁张一鸣创业成功秘密武器,OKR“失控”管理法
  14. 腾讯与阿里巴巴投资可编程芯片公司Barefoot Networks
  15. H5微信授权登录 H5支付 外部浏览器微信支付 前端一个函数搞
  16. 数据湖和数据仓库的区别是什么?
  17. 分形图(fractal pictures)
  18. 第一个Java程序Hello World(IG牛逼)
  19. 在键盘上怎么点出来上下居中的点?
  20. C语言 信号集回调函数 避免子进程在信号回调注册完成之前全部结束

热门文章

  1. 全球及中国电子不停车收费系统(ETC)行业竞争模式及十四五建设现状分析报告2021-2027年
  2. shell脚本——循环语句
  3. Fall2018 学期规划(09/16修订)
  4. python 循环嵌套例子_Python循环嵌套案例-打印九九乘法表
  5. 魅族打开Android彩蛋,魅族 Flyme Android 10 首个内测版本已推送 强制开启 90Hz 彩蛋...
  6. 粤电博贺码头计算机管理系统中标,粤电博贺煤炭码头项目档案顺利通过省交通运输厅专项验收...
  7. Unity修改分辨率优化游戏性能
  8. 高并发核心编程Spring Cloud+Nginx秒杀实战,秒杀业务的参考实现
  9. 微信小程序 wx:for/if/elif/else等循环的写法以及wx.key的运用
  10. ubuntu 桌面卡死 解决方法