Android 7.0 Keyguard流程分析

来源:互联网 发布:海安东华软件招聘 编辑:程序博客网 时间:2024/05/18 17:27

在android 6.0 上Keyguard作为了SystemUI的一个库文件被引用,所以编译的时候不会出现Keyguard.apk这个文件,Keyguard也伴随着SystemUI的启动而启动,其中最重要的一个文件就是KeyguardViewMediator,这个文件负责SystemUI与Keyguard的交互,我们来看一下这个文件的启动。


一.KeyguardViewMediator的启动

KeyguardViewMediator.java作为SystemUIApplication.java中SERVICES[]中的一个元素,我们用一个流程图来说明这个文件的启动过程,这个数组中的其它元素启动顺序与这个类似,只是功能不同而已。


从上面的流程图中可以看到KeyguardViewMediator.java的启动分为两部分。

1.SystemUIApplication.java的onstart()

SystemUIApplication.java的onstart()调用,这个调用会初始化锁屏相关的工具类,但是需要注意这个步骤中没没有初始化任何锁屏界面相关的东西,只是进行一些Intent的注册以及一些必要的初始化工作。其中KeyguardDisplayManager.java会作为中间类去控制keyguard的show与hide,KeyguardUpdateMonitor.java中注册了绝大多数的广播,负责处理界面的一些刷新流程处理,还有一个需要特别注意一下就是FingerManager.java,这个类是android 6.0 新添加的,负责处理一些指纹相关的东西。

2.SystemUIApplication的onBootCompleted()

这个函数会去发送锁屏加载完成的广播,USER_PRESENT_INTENT,但是需要注意这个函数的调用时机。这个函数的调用是received到系统发送的ACTION_BOOT_COMPLETED,根据实际工作中的经验,ACTION_BOOT_COMPLETED的发送比较偏后,在系统绝大多数的界面处理完成以后才会发送,在看到锁屏之后,也就是说,如果我们监听到USER_PRESENT_INTENT,那么锁屏一般是肯定加载完成了的。

备注:锁屏界面的初始化是在SystemBar.java的onStart()方法中处理的,这个方法比较复杂,我们在SystemUI的分析中在细说。初始化是在onStart(),但是锁屏的加载需要经过一些特殊条件的触发与判断,由于开机第一次锁屏的加载是需要经过ActivityManagerService.java中界面的判断与WindowMnaagerService.java中界面绘制的处理才决定是否显示,牵扯的比较负责,暂时不分析,后续专门分析这部分。

二.SystemUI的启动

Keyguard是SystemUI的一个库文件,所以分析Keyguard我们需要先看一下SystemUI的启动。流程图简单分析如下:

PhoneStatusBar.java中的createAndAddWindows()会初始化并且加载SystemUI的绝大多数界面,包括statusbar与navigationbar,以及初始化QSHostView。这部分代码需要仔细阅读代码,注意细节,用到这些细节的时候我们再仔细分析。

至此,keyguard以及systemUI启动初始化加载完毕,SystemService.java中的startSystemUI()函数执行完毕。

三.POWER键灭屏时Keyguard的加载

我们知道用power键灭屏的时候会加载keyguard,这样可以保证亮屏的时候终端用户可以第一时间看到锁屏,保证良好的用户体验,我们用这个场景来分析锁屏的加载过程。

1.PowerManagerService亮屏流程


上述流程图从power按键的分发到PowerManagerService.java的处理,再到keyguard相关的代码处理,这条线路传到KeyguardViewMediator.java中以后就要开始锁屏界面的绘制了。稍后专门对锁屏界面的绘制进行说明。

备注:
亮屏过程中涉及到两条关键的线程,分别是PowerManager Notifier Thread 与DisplayManager Thread。
1.PowerManager Notifier Thread:power按键事件传到PowerManagerService.java中以后会分为两条线路进行事件处理,一条就是我们上面流程图上标注的,这条Thread(Notifier.java)主要负责亮屏或者灭屏广播的发送,以及锁屏界面的加载。
2.DisplayManager Thread:这条Thread会传送到DisplayManagerService.java中去,会负责进行屏幕状态的设置以及屏幕的熄灭与点亮(真正的屏幕操作者),此外跟屏幕相关的一些可见性操作都是这条Thread(DisplayPowerController.java)进行处理,例如屏幕亮度的变化、屏幕亮度的设置、屏幕的显示时机等等,非常重要,有时间可以研究研究。

2.KeyguardManager.java的说明

APP侧开发锁屏应用,调用的接口是KeyguardManager.java或者内部类KeyguardManager.KeyguardLock,用这个manager来获取或者设置锁屏的一些状态,这样就可以控制锁屏的显示。需要添加对于的权限到AndroidMainfest.xml文件中,android.permission.DISABLE_KEYGUARD。
对这个类的详细介绍以及用法介绍请参考如下网址:http://blog.csdn.net/hudashi/article/details/7073373
我们简单的来分析一下这个调用过程,也用流程图来说明一下

从这个流程图不难发现,不管APP侧怎么调用KeyguardManager.java的接口,最终的实现都是在KeyguardViewMediator.java中。KeyguardService.java是Binder的服务器端,客户端是KeyguardServiceDelegate.java,KeyguardServiceDelegate.java这个文件在调用过程中只起到过渡的左右,在这里并没有深入研究。KeyguardService.java会将所有的调用传递到KeyguardViewMediator.java中。
备注:
Android 6.0 的Keyguard是在SystemUI中控制的,SystemUI是一个系统级的APK,要操作锁屏还是需要使用上述这些东西。所以如果需要改变锁屏的一些流程,我们可以在合适的位置调用KeyguardManager.java中接口,或者添加一些客制化的东西,直接在KeyguardViewMediator.java中进行操作,都是可以实现的。

3.锁屏的加载绘制过程

KeyguardViewMediator.java的onFinishedGoingToSleep()是加载锁屏的入口,接下来对这个过程进行分析。
这个过程是开机以后正常使用过程中,用power键灭屏的时候加载锁屏的流程,并且存在锁屏方式。还有其它方式的灭屏跟这个略有区别,例如亮屏超时的熄屏,但是大同小异,根本是一样的,有时间再仔细分析。


这样经过上述的流程以后,keyguard就在锁屏界面显示了,需要注意的是Android 6.0 上看到的锁屏实际上是一层通知panelview,也就是流程图上的17,如果去掉这个函数,那么界面上是不会出现通知界面的,但是锁屏也是不能用的,因为在这个函数执行之前已经通知了系统要加载锁屏,所以结果就是看上去去掉了notificationpanelview,但是实际上系统中的状态还是存在这个界面的,所以如果要从keyguard中用代码去掉这个界面,还需要其它的一些修改,需要保持界面状态的一致。

需要注意这个过程中的26:updateState(),这个函数会去更新keyguard以及systemUI的一些标志状态,保持系统状态的统一性,27会去设置更新后的这些状态值。

备注:

在这个过程中,使用了几次Handle,Handle的使用使得从log上看流程跟诡异,这是由于handle消息处理机制导致的,这个流程处理下来加了大量的状态判断,所以并不会对结果造成什么影响,只是分析问题查看log的时候可能需要注意一下这个情况。

四.锁屏方式的保存

系统在加载keyguard的时候需要先判断当前系统中是否有锁屏方式,那么锁屏方式又是如何保存的了?需要分析一下:

研究锁屏方式的保存可以从Settings 里的设置锁屏方式作为入口,ChooseLockGeneric.java。在这个文件中我们找到了锁屏的工具了,LockPathernUtils.java,锁屏方式的获取以及锁屏方式的保存都依靠这个类来进行,所以如果需要修改默认锁屏方式或者初始化锁屏方式有什么特殊的需求,可以直接改LockPathernUtils.java中对应的默认方式,本地实验过,都是可行的,副作用最小。

锁屏方式的保存与检测最后都会调用到framework层去,这部分比较复杂,后续会有专门的部分来说明framework中的锁屏方式。

五.锁屏界面解锁分析

1.onInterceptTouchEvent和onTouchEvent调用时序

解锁动作是由手势触发的,在研究解锁流程之前需要明白onInterceptTouchEvent与onTouchEvent的区别与使用。

onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,Android这么设计的想法也很好理解,由于ViewGroup会包含若干childView,因此需要能够统一监控各种touch事件的机会,因此纯粹的不能包含子view的控件是没有这个方法的,如LinearLayout就有,TextView就没有。
onInterceptTouchEvent()使用也很简单,如果在ViewGroup里覆写了该方法,那么就可以对各种touch事件加以拦截。但是如何拦截,是否所有的touch事件都需要拦截则是比较复杂的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各个childView间的传递机制完全取决于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,针对down事件处理的返回值直接影响到后续move和up事件的接收和传递。
关于返回值的问题,基本规则很清楚,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。

由于onInterceptTouchEvent()的机制比较复杂,总结一下,基本的规则是:
1.down事件首先会传递到onInterceptTouchEvent()方法
2.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。
3.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。
4.如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。
5.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

下面用一个简单的实验说明上述复杂的规则。视图自底向上共3层,其中LayoutView1和LayoutView2就是LinearLayout,MyTextView就是TextView:

通常外围的layoutview1,layoutview2,只是布局的容器不需要响应触屏的点击事件,仅仅Mytextview需要相应点击。但这只是一般情况,一些特殊的布局可能外围容器也要响应,甚至不让里面的mytextview去响应。更有特殊的情况是,动态更换响应对象。
那么首先看一下默认的触屏事件的在两个函数之间的传递流程。如下图:


如果仅仅想让MyTextView来响应触屏事件,让MyTextView的OnTouchEvent返回true,那么事件流就变成如下图,可以看到layoutview1,layoutview2已经不能进入OnTouchEvent:


另外一种情况,就是外围容器想独自处理触屏事件,那么就应该在相应的onInterceptTouchEvent函数中返回true,表示要截获触屏事件,比如layoutview1作截获处理,处理流变成如下图:


以此类推,我们可以得到各种具体的情况,整个layout的view类层次中都有机会截获,而且能看出来外围的容器view具有优先截获权。
当我们去做一些相对来讲具有更复杂的触屏交互效果的应用时候,经常需要动态变更touch event的处理对象,比如launcher待机桌面和主菜单(见下图),从滑动屏幕开始到停止滑动过程当中,只有外围的容器view才可以处理touch event,否则就会误点击上面的应用图标或者widget.反之在静止不动的状态下则需要能够响应图标(子view)的touch事件

2.解锁流程

(1)notification界面的滑动

Android L上, 锁屏分为两个界面, 一个是可以显示notification的界面(称为Notification Keyguard), 另一个是在Notification Keyguard界面向上滑之后出现输入密码的界面(称为bouncer). 只有在设置为安全锁(非滑动锁)的情况下, 才会显示bouncer界面.
在Notification Keyguard界面上滑动时, 它有去检查滑动的Y-距离长度, 只有大于一定的阈值才会触发解锁.
这个阈值是在如下文件中定义的, 它是用下面的值乘以一个因子(1.5)之后得到这个Y-距离.

[html] view plain copy
  1. 1.alps/frameworks/base/packages/SystemUI/res/values/Dimens.xml  
  2. 2.<dimen name="unlock_falsing_threshold">80dp</dimen>  
对于在Notification Keyguard界面向上滑动没有解锁或者没有显示出bouncer界面的情况, 可如下加log验证是不是因为滑动距离小于阈值引起.
添加如下log后, 在问题时间点搜索log "onTrackingStarted begin" 和 "onTrackingStopped begin", 这两句log是成对出现的, 在手指按下在屏幕上开始滑时会打印"onTrackingStarted begin", 松开离开屏幕时会打印"onTrackingStopped begin", 搜索到这对log后, 寻找离"onTrackingStopped begin"最近的关于"-h="的log, "-h"表示的就是滑动的高度, 检查下打印的这个高度和阈值的比较. 如果在正常情况下, 向上滑动解锁体验不是很好的原因是由于这个高度小于阈值所致, 可适当修改将这个阈值改小.

[java] view plain copy
  1. PhoneStatusBar.java  
  2. public void onTrackingStarted(){  
  3.     Log.d(TAG, "onTrackingStarted begin"); //添加这行  
  4.  ...  
  5. }  
  6.   
  7. public void onTrackingStopped(){  
  8.     Log.d(TAG, "onTrackingStopped begin"); //添加这行  
  9.  ...  
  10. }  
  11.   
  12.   
  13. PanelView.java  
  14. public boolean onTouchEvent(MotionEvent event){  
  15.     ...  
  16.  case MotionEvent.ACTION_MOVE:  
  17.       ...  
  18.    Log.d(TAG, "-h="+(-h)+" getFalsingThreshold()="+getFalsingThreshold());         //添加这行  
  19.    if(-h >= getFalsingThreshold()){  
  20.         mTouchAboveFalsingThreshold = true;  
  21.    }  
  22.    ...  
  23.  ...  
  24. }  

onTrackingStarted()的调用流程如下:

[java] view plain copy
  1. 09-20 09:47:15.896 W/yangjie ( 1276): java.lang.RuntimeException: here  
  2.   
  3. 09-20 09:47:15.896 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.PanelView.onTrackingStarted(PanelView.java:438)  
  4.   
  5. 09-20 09:47:15.896 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.NotificationPanelView.onTrackingStarted(NotificationPanelView.java:1868)  
  6.   
  7. 09-20 09:47:15.896 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.PanelView.onTouchEvent(PanelView.java:311)  
  8.   
  9. 09-20 09:47:15.896 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.NotificationPanelView.onTouchEvent(NotificationPanelView.java:774)  
  10.   
  11. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.View.dispatchTouchEvent(View.java:9415)  
  12.   
  13. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2660)  
  14.   
  15. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2304)  
  16.   
  17. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2666)  
  18.   
  19. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)  
  20.   
  21. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2666)  
  22.   
  23. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)  
  24.   
  25. 09-20 09:47:15.896 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.StatusBarWindowView.dispatchTouchEvent(StatusBarWindowView.java:208)  
  26.   
  27. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.View.dispatchPointerEvent(View.java:9646)  
  28.   
  29. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4738)  
  30.   
  31. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4596)  
  32.   
  33. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4101)  
  34.   
  35. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4154)  
  36.   
  37. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4120)  
  38.   
  39. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4266)  
  40.   
  41. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4128)  
  42.   
  43. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4323)  
  44.   
  45. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4101)  
  46.   
  47. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4154)  
  48.   
  49. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4120)  
  50.   
  51. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4128)  
  52.   
  53. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4101)  
  54.   
  55. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6555)  
  56.   
  57. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6529)  
  58.   
  59. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6472)  
  60.   
  61. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6727)  
  62.   
  63. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)  
  64.   
  65. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)  
  66.   
  67. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)  
  68.   
  69. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:6686)  
  70.   
  71. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:6753)  
  72.   
  73. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)  
  74.   
  75. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.Choreographer.doCallbacks(Choreographer.java:696)  
  76.   
  77. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.Choreographer.doFrame(Choreographer.java:625)  
  78.   
  79. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)  
  80.   
  81. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.os.Handler.handleCallback(Handler.java:815)  
  82.   
  83. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.os.Handler.dispatchMessage(Handler.java:104)  
  84.   
  85. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.os.Looper.loop(Looper.java:207)  
  86.   
  87. 09-20 09:47:15.896 W/yangjie ( 1276):   at android.app.ActivityThread.main(ActivityThread.java:5692)  
  88.   
  89. 09-20 09:47:15.896 W/yangjie ( 1276):   at java.lang.reflect.Method.invoke(Native Method)  
  90.   
  91. 09-20 09:47:15.896 W/yangjie ( 1276):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)  
  92.   
  93. 09-20 09:47:15.896 W/yangjie ( 1276):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:766)  

onTrackingStopped()的调用流程如下:

[java] view plain copy
  1. 09-20 09:47:16.014 W/yangjie ( 1276): java.lang.RuntimeException: here  
  2.   
  3. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.PanelView.onTrackingStopped(PanelView.java:426)  
  4.   
  5. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.NotificationPanelView.onTrackingStopped(NotificationPanelView.java:1881)  
  6.   
  7. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.PanelView.endMotionEvent(PanelView.java:396)  
  8.   
  9. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.PanelView.onTouchEvent(PanelView.java:335)  
  10.   
  11. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.NotificationPanelView.onTouchEvent(NotificationPanelView.java:774)  
  12.   
  13. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.View.dispatchTouchEvent(View.java:9415)  
  14.   
  15. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2660)  
  16.   
  17. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2304)  
  18.   
  19. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2666)  
  20.   
  21. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)  
  22.   
  23. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2666)  
  24.   
  25. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)  
  26.   
  27. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.systemui.statusbar.phone.StatusBarWindowView.dispatchTouchEvent(StatusBarWindowView.java:208)  
  28.   
  29. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.View.dispatchPointerEvent(View.java:9646)  
  30.   
  31. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4738)  
  32.   
  33. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4596)  
  34.   
  35. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4101)  
  36.   
  37. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4154)  
  38.   
  39. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4120)  
  40.   
  41. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4266)  
  42.   
  43. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4128)  
  44.   
  45. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4323)  
  46.   
  47. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4101)  
  48.   
  49. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4154)  
  50.   
  51. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4120)  
  52.   
  53. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4128)  
  54.   
  55. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4101)  
  56.   
  57. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6555)  
  58.   
  59. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6529)  
  60.   
  61. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6472)  
  62.   
  63. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6727)  
  64.   
  65. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)  
  66.   
  67. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.os.MessageQueue.nativePollOnce(Native Method)  
  68.   
  69. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.os.MessageQueue.next(MessageQueue.java:328)  
  70.   
  71. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.os.Looper.loop(Looper.java:164)  
  72.   
  73. 09-20 09:47:16.014 W/yangjie ( 1276):   at android.app.ActivityThread.main(ActivityThread.java:5692)  
  74.   
  75. 09-20 09:47:16.014 W/yangjie ( 1276):   at java.lang.reflect.Method.invoke(Native Method)  
  76.   
  77. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)  
  78.   
  79. 09-20 09:47:16.014 W/yangjie ( 1276):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:766)  
  80.   
  81. 09-20 09:47:16.015 D/StatusBarKeyguardViewManager( 1276): dismiss(authenticated = false) is called. mScreenOn = true  
  82.   
  83. 09-20 09:47:16.015 D/KeyguardBouncer( 1276): show(resetSecuritySelection = false  
  84.   
  85. 09-20 09:47:16.016 D/KeyguardSecurityView( 1276): showNextSecurityScreenOrFinish(false)  
  86.   
  87. 09-20 09:47:16.016 D/KeyguardSecurityView( 1276): showNext.. mCurrentSecuritySelection = Pattern  
  88.   
  89. 09-20 09:47:16.016 D/KeyguardViewMediator( 1276): updateNavbarStatus() is called.  
  90.   
  91. 09-20 09:47:16.016 D/KeyguardSecurityView( 1276): showNextSecurityScreenOrFinish() - return finish = false  
  92.   
  93. 09-20 09:47:16.016 D/KeyguardBouncer( 1276): show() - try to dismiss "Bouncer" directly.  

从上面的调用栈可以看到,调用从PanelView.java的onTouchEvent()开始做的区分,所以如果我们有什么问题是关于触摸后的一些情况的,可以在这个文件的这个函数中打log以及一些调用栈来确定问题。
从上面的onTrackingStopped()的最后log可以看到,这个函数调用结束以后会调用keyguard的show()来展示具体的锁屏界面。

(2)锁屏界面的解锁

对应不同的锁屏界面有不同的方式去处理,包括KeyguardPatternView.java、KeyguardPasswordView.java、KeyguardPINView.java等等方式,都有各自的处理方式,但是如果解锁输入正确,那么都会去调用KeyguardBouncer.java中的hide()与removeView()函数,我们在这两个方法中添加对应的异常调用栈来定位调用过程。
解锁失败等情况下下面的framework层的分析,根据这个过程添加log可以定位问题原因,具体的调用过程就不再分析了。

(3)根据异常栈来定位调用顺序

具体这两个方法会在什么时候调用,可以使用打印异常调用栈的方式来确定这个调用过程:

六.framework层Keyguard 的保存与读取

1.背景资料

(1)Android M 之前锁屏密码的存储

在 Android M 之前,锁屏密码的存储格式很简单,其使用了 64 位随机数作为 salt 值,此 salt 值被存储在 SQLite 数据库 /data/system/locksettings.db 中。密码在存储的时候,会将输入的密码加上此随机数组成新的字符串。然后对新的字符串分别进行 SHA-1 和 MD5 加密,将加密后的密文通过 MD5 + SHA-1 的方式进行字符串拼接,组成新的密文存储在 /data/system/password.key 中,共有 72 位。其加密后的形式如下:
[java] view plain copy
  1. /data/system # cat password.keyB40C2F6FE4E89F3386D4E689B135304410D64951914FB35770FDAC58B694177B29297A80  

而密码的详细信息,存储在 /data/system/device_policies.xml 中,内容类似如下:

[java] view plain copy
  1. /data/system # cat device_policies.xml  


其中主要用到的两个字段 quality 是密码的类型,简单密码和复杂密码的值不同,length 是密码的长度,其他字段存储密码中各种字符的数量。

(2)Android M 中锁屏密码的存储

在 Android M 中,锁屏密码的存储格式发生了变化,其默认的存储格式在/system/gatekeeper/include/gatekeeper/password_handle.h 中描述如下:
[java] view plain copy
  1. typedef uint64_t secure_id_t;  
  2. typedef uint64_t salt_t;  
  3. /**  
  4. * structure for easy serialization  
  5. * and deserialization of password handles.  
  6. */  
  7. static const uint8_t HANDLE_VERSION = 2;  
  8. struct __attribute__ ((__packed__))   
  9. password_handle_t {      
  10. // fields included in signature      
  11. uint8_t version;      
  12. secure_id_t user_id;      
  13. uint64_t flags;      
  14. // fields not included in signature      
  15. salt_t salt;      
  16. uint8_t signature[32];      
  17. bool hardware_backed;  
  18. };  
其中 version 默认是 2,user_id 是 Android 用户 id ,signature 存储的便是密文,hardware_backed 存储的是加密方式,0 表示密文是软件加密,而 1 表示密文是通过 TEE 环境进行加密得到的。
密码加密后默认以 password_handle_t 格式存储在/data/system/gatekeeper.password.key 中。密码的生成和校验,在 HAL 层是通过 system/core/gatekeeperd/gatekeeperd.cpp 中的函数实现的。其在系统启动时被注册为 gatekeeperd 服务,服务在启动的时候会调用 GateKeeperProxy()对象,此类的构造函数会去查找 TEE module,如果找到,则通过 TEE 设备进行加解密,如果没有找到,则通过一个软件设备进行加解密。

Android M引入了GateKeeper,锁屏的密码都存储在此模块中,GateKeeper分software和hardware两种,同时只能使用一种。


Keyguard/choose lock,使用lockSettings的模块。
LockSetings:这个模块包括LockPatternUtils.java, LockSettingsStorage.java, LockSettingsService.kava
Native层,gatekeeper相关类的关系图及其路径:

常见Hardware gatekeeper的代码路径:
/vendor/mediatek/proprietary/trustzone/trustonic/source/bsp/platform/mt6752/gatekeeper/TlcTeeGatekeeper/
/vendor/mediatek/proprietary/trustzone/trustonic/source/external/gatekeeper/common/302c/
/vendor/mediatek/proprietary/trustzone/trustonic/source/bsp/platform/mt6735/gatekeeper/TlcTeeGatekeeper/

2.无法解锁、解锁较慢或者注册锁慢问题

从上述的背景,知道注册密码,验证都是经过LockSettingsService,再到GateKeeper。遇到无法解锁、解锁较慢或者注册锁慢的,可以在这条逻辑路径上加入debug log,在分析是属于哪个模块的问题。
以下log红色部分与解锁相关,橙色部分与设置锁相关。依据你的问题来决定加哪一种,或者两者都加。

(1) java层分析

/frameworks/base/services/core/java/com/android/server/LockSettingsService.java
[java] view plain copy
  1. public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {  
  2.   
  3. +      Slog.d(TAg, "checkPattern"); //这里是slog,在吐sys log文件中return doVerifyPattern(pattern, false, 0, userId);  
  4. }  
[java] view plain copy
  1.    private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,long challenge, int userId) throws RemoteException {  
  2.        checkPasswordReadPermission(userId);  
  3.   
  4. +      Slog.d(TAg, "doVerifyPattern start");CredentialHash storedHash = mStorage.readPatternHash(userId);  
  5.   
  6. +      Slog.d(TAg, "read pattern hash");boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;  
  7.   
  8.        ...  
  9.   
  10.        VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,hasChallenge, challenge,new CredentialUtil() {...}  
  11.        );  
  12. +      Slog.d(TAg, "verifyCredential response code: response.getResponseCode()");if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK  
  13.                && shouldReEnrollBaseZero) {  
  14.            setLockPattern(pattern, patternToVerify, userId);  
  15.        }  
  16. +      Slog.d(TAg, "doVerifyPattern end");return response;  
  17.   
  18.     }  
[java] view plain copy
  1.  private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,  
  2.             String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)  
  3.                 throws RemoteException {  
  4.         ...  
  5. +       Slog.d(TAG, "hasChallenge: " + hasChallenge);if (hasChallenge) {  
  6.             byte[] token = null;  
  7.             GateKeeperResponse gateKeeperResponse = getGateKeeperService()  
  8.                     .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());  
  9.   
  10.             ...  
  11. +           Slog.d(TAG, "verify response " + response);  
  12.         } else {  
  13.             GateKeeperResponse gateKeeperResponse = getGateKeeperService().verify(  
  14.                     userId, storedHash.hash, credential.getBytes());   
  15.   
  16.        ...  
  17. +           Slog.d(TAG, "verify response " + response);  
  18.         }  
  19.   
  20.         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {  
  21.             // credential has matchedunlockKeystore(credential, userId);  
  22.             if (shouldReEnroll) {  
  23.                 credentialUtil.setCredential(credential, credential, userId);  
  24.             }  
  25.   
  26. +           Slog.d(TAG, "verify ok");  
  27.         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {  
  28.             if (response.getTimeout() > 0) {  
  29.                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);  
  30.             }  
  31.   
  32. +           Slog.d(TAG, "verify fail, retry ");  
  33.         }  
  34.   
  35.         return response;  
  36.     }  
[java] view plain copy
  1. public void setLockPattern(String pattern, String savedCredential, int userId)  
  2.             throws RemoteException {  
  3.         checkWritePermission(userId);  
  4.         byte[] currentHandle = getCurrentHandle(userId);  
  5. +       Slog.d(TAG, "setLockPattern");if (pattern == null) {  
  6.             getGateKeeperService().clearSecureUserId(userId);  
  7.             mStorage.writePatternHash(null, userId);  
  8.             setKeystorePassword(null, userId);  
  9.             return;  
  10.         }  
  11.         ...  
  12.         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);  
  13.         if (enrolledHandle != null) {  
  14.   
  15. +           Slog.d(TAG, "writePatternHash ");mStorage.writePatternHash(enrolledHandle, userId);  
  16.         } else {  
  17.             Slog.e(TAG, "Failed to enroll pattern");  
  18.         }  
  19.   
  20. +       Slog.d(TAG, "setLockPattern done!");  
  21.     }  
  22.     @Overridepublic void setLockPassword(String password, String savedCredential, int userId)  
  23.             throws RemoteException {  
  24.        checkWritePermission(userId);  
  25.         byte[] currentHandle = getCurrentHandle(userId);  
  26. +       Slog.d(TAG, "setLockPassword");if (password == null) {  
  27.             getGateKeeperService().clearSecureUserId(userId);  
  28.             mStorage.writePasswordHash(null, userId);  
  29.             setKeystorePassword(null, userId);  
  30.             return;  
  31.         }  
  32.   
  33.         ...  
  34.         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);  
  35.         if (enrolledHandle != null) {  
  36.   
  37. +           Slog.d(TAG, "writePatternHash ");mStorage.writePasswordHash(enrolledHandle, userId);  
  38.         } else {  
  39.             Slog.e(TAG, "Failed to enroll password");  
  40.         }  
  41.   
  42. +       Slog.d(TAG, "setLockPassword done!");  
  43.     }  
[java] view plain copy
  1.     private byte[] enrollCredential(byte[] enrolledHandle,  
  2.             String enrolledCredential, String toEnroll, int userId)  
  3.             throws RemoteException {  
  4.         ...  
  5.   
  6. +       Slog.d(TAG, "enroll start.");GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,  
  7.                 enrolledCredentialBytes, toEnrollBytes);  
  8. +       Slog.d(TAG, "enroll finish.");  
  9.   
  10. if (response == null) {  
  11.             return null;  
  12.         }  
  13.   
  14.         byte[] hash = response.getPayload();  
  15.         if (hash != null) {  
  16.   
  17. +           Slog.d(TAG, "setKeystorePassword.");setKeystorePassword(toEnroll, userId);  
  18.         } else {  
  19.             // Should not happenSlog.e(TAG, "Throttled while enrolling a password");  
  20.         }  
  21.   
  22. +       Slog.d(TAG, "enrollCredential done.");return hash;  
  23.     }  

/frameworks/base/core/java/com/android/internal/widget/LockPatternUtils.java

[java] view plain copy
  1.     public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern,  
  2.             boolean isFallback, String fallbackFor, int userId) {  
  3.         try {  
  4.             if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {  
  5.                 throw new IllegalArgumentException("pattern must not be null and at least "  
  6.                         + MIN_LOCK_PATTERN_SIZE + " dots long.");  
  7.             }  
  8. +           Log.d(TAG, "saveLockPattern begin. ");  
  9.   
  10. getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);  
  11.   
  12. +           Log.d(TAG, "saveLockPattern end. ");DevicePolicyManager dpm = getDevicePolicyManager();  
  13.   
  14.             // Update the device encryption password.if (userId == UserHandle.USER_OWNER  
  15.                     && LockPatternUtils.isDeviceEncryptionEnabled()) {  
  16.                 if (!shouldEncryptWithCredentials(true)) {  
  17.                     clearEncryptionPassword();  
  18.                 } else {  
  19.                     String stringPattern = patternToString(pattern);  
  20.                     updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);  
  21.                 }  
  22.             }  
  23. +           Log.d(TAG, "update encrypt password ");  
  24.   
  25. setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);  
  26.   
  27.             ...  
  28.   
  29. +           Log.d(TAG, set pawword type finish.");onAfterChangingPassword(userId);  
  30.         } catch (RemoteException re) {  
  31.             Log.e(TAG, "Couldn't save lock pattern " + re);  
  32.         }  
  33.   
  34. +       Log.d(TAG, "saveLockPattern end. ");  
  35.     }  
[java] view plain copy
  1.   public void saveLockPassword(String password, String savedPassword, int quality,  
  2.             boolean isFallback, String fallbackFor, int userHandle) {  
  3.         try {  
  4.              ...  
  5.   
  6.   
  7. +           Log.d(TAG, "saveLockPassowrd start.");getLockSettings().setLockPassword(password, savedPassword, userHandle);  
  8.   
  9. +           Log.d(TAG, "saveLockPassowrd start.");int computedQuality = computePasswordQuality(password);  
  10.   
  11.             ...  
  12. +           Log.d(TAG, "is fallback: " + isFallback);if (!isFallback) {  
  13.                ...  
  14.             } else {  
  15.                ...  
  16.             }  
  17.            ...  
  18.   
  19. +          Log.d(TAG, "saveLockPassword done.");  
  20.         } catch (RemoteException re) {  
  21.             // Cant do muchLog.e(TAG, "Unable to save lock password " + re);  
  22.         }  
  23.     }  

(2)native层分析

/system/gatekeeper/Android.mk
[java] view plain copy
  1. LOCAL_CFLAGS = -Wall -Werror -g LOCAL_MODULE_TAGS := optional  
  2.   
  3. LOCAL_SHARED_LIBRARIES := liblog  

/system/gatekeeper/gatekeeper.cpp

[java] view plain copy
  1. + #define LOG_TAG "gatekeeperd"+ #include <cutils/log.h>+ #include <utils/Log.h>  
 void GateKeeper::Verify(const VerifyRequest &request, VerifyResponse *response) {

[java] view plain copy
  1.     if (response == NULL) return;  
  2.   
  3.     ...  
  4.   
  5.   
  6. +   ALOGI("Verify: version %d", password_handle->version);if (password_handle->version > HANDLE_VERSION) {  
  7.         response->error = ERROR_INVALID;  
  8.         return;  
  9.     }  
  10.   
  11.     secure_id_t user_id = password_handle->user_id;  
  12.     secure_id_t authenticator_id = 0;  
  13.     uint32_t uid = request.user_id;  
  14.   
  15.     uint64_t timestamp = GetMillisecondsSinceBoot();  
  16.   
  17.     uint32_t timeout = 0;  
  18.     bool throttle = (password_handle->version >= HANDLE_VERSION_THROTTLE);  
  19.     bool throttle_secure = password_handle->flags & HANDLE_FLAG_THROTTLE_SECURE;  
  20.   
  21.   
  22.   
  23. +   ALOGI("throttle: %d, throttle_secure: %d", (throttle? 1:0), (throttle_secure? 1:0));if (throttle) {  
  24.         failure_record_t record;  
  25.   
  26. +       ALOGI("GetFailureRecord"); //GetFailtureRecord具体有soft或hard的gatekeeper实现if (!GetFailureRecord(uid, user_id, &record, throttle_secure)) {  
  27.             response->error = ERROR_UNKNOWN;  
  28.             return;  
  29.         }  
  30.   
  31.   
  32. +       ALOGI("ThrottleRequest");if (ThrottleRequest(uid, timestamp, &record, throttle_secure, response)) return;  
  33.   
  34.   
  35. +       ALOGI("IncrementFailureRecord");if (!IncrementFailureRecord(uid, user_id, timestamp, &record, throttle_secure)) {  
  36.             response->error = ERROR_UNKNOWN;  
  37.             return;  
  38.         }  
  39.   
  40.         timeout = ComputeRetryTimeout(&record);  
  41.   
  42. +       ALOGI("ComputeRetryTimeout %d", timeout);  
  43.     } else {  
  44.         response->request_reenroll = true;  
  45.   
  46. +       ALOGI("reenroll");  
  47.     }  
  48.   
  49.     if (DoVerify(password_handle, request.provided_password)) {//校验函数  
  50.         // Signature matchesUniquePtr<uint8_t> auth_token_buffer;  
  51.         uint32_t auth_token_len;  
  52.         MintAuthToken(&auth_token_buffer, &auth_token_len, timestamp,  
  53.                 user_id, authenticator_id, request.challenge);  
  54.   
  55.         SizedBuffer auth_token(auth_token_len);  
  56.         memcpy(auth_token.buffer.get(), auth_token_buffer.get(), auth_token_len);  
  57.         response->SetVerificationToken(&auth_token);  
  58.         if (throttle) ClearFailureRecord(uid, user_id, throttle_secure);  
  59.     } else {  
  60.         // compute the new timeout given the incremented recordif (throttle && timeout > 0) {  
  61.             response->SetRetryTimeout(timeout);  
  62.         } else {  
  63.             response->error = ERROR_INVALID;  
  64.         }  
  65.     }  
  66.   
  67.   
  68.   
  69. +   ALOGI("Verify: error is %d", response->error); //校验结束  
  70. }  
[java] view plain copy
  1. bool GateKeeper::CreatePasswordHandle(SizedBuffer *password_handle_buffer, salt_t salt,  
  2.         secure_id_t user_id, uint64_t flags, uint8_t handle_version, const uint8_t *password,  
  3.         uint32_t password_length) {  
  4.     ...  
  5. +   ALOGI("CreatePasswordHandle");const uint8_t *password_key = NULL;  
  6.     uint32_t password_key_length = 0;  
  7.     GetPasswordKey(&password_key, &password_key_length);  
  8. +   ALOGI("password lenght: %d", password_key_length);if (!password_key || password_key_length == 0) {  
  9.         return false;  
  10.     }  
  11.   
  12.     ComputePasswordSignature(password_handle->signature, sizeof(password_handle->signature), //ComputePasswordSignature由具体的soft或者hard gatekeeper实现。  
  13.             password_key, password_key_length, to_sign, sizeof(to_sign), salt);  
  14.   
  15. +   ALOGI("CreatePasswordHandle end");return true;  
  16. }  

/system/core/gatekeeperd/gatekeeperd.cpp

[java] view plain copy
  1.     virtual int enroll(uint32_t uid,  
  2.             const uint8_t *current_password_handle, uint32_t current_password_handle_length,  
  3.             const uint8_t *current_password, uint32_t current_password_length,  
  4.             const uint8_t *desired_password, uint32_t desired_password_length,  
  5.             uint8_t **enrolled_password_handle, uint32_t *enrolled_password_handle_length) {  
  6.         ...  
  7.   
  8. +       ALOGI("enroll");  
  9.         if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {  
  10.             return PERMISSION_DENIED;  
  11.         }  
  12.   
  13.         // need a desired password to enrollif (desired_password_length == 0) return -EINVAL;  
  14.   
  15.         int ret;  
  16.         if (device) {  
  17.                ...  
  18. +           ALOGI("hardware gatekeeper enroll begin.");ret = device->enroll(device, uid, current_password_handle, current_password_handle_length,  
  19.                     current_password, current_password_length,  
  20.                     desired_password, desired_password_length,  
  21.                     enrolled_password_handle, enrolled_password_handle_length);  
  22.   
  23.   
  24.         } else {  
  25.   
  26. +           ALOGI("soft gatekeeper enroll begin.");ret = soft_device->enroll(uid,  
  27.                     current_password_handle, current_password_handle_length,  
  28.                     current_password, current_password_length,  
  29.                     desired_password, desired_password_length,  
  30.                     enrolled_password_handle, enrolled_password_handle_length);  
  31.         }  
  32.   
  33. +       ALOGI("enroll end. ret: %d", ret);  
  34.   
  35.         if (ret == 0) {  
  36.             gatekeeper::password_handle_t *handle =  
  37.                     reinterpret_cast<gatekeeper::password_handle_t *>(*enrolled_password_handle);  
  38.             store_sid(uid, handle->user_id);  
  39.             bool rr;  
  40.   
  41.   
  42. +           ALOGI("internal verify begin. ");// immediately verify this password so we don't ask the user to enter it again// if they just created it.verify(uid, *enrolled_password_handle, sizeof(password_handle_t), desired_password,  
  43.                     desired_password_length, &rr);  
  44.   
  45. +           ALOGI("internal verify end. ");  
  46.         }  
  47.   
  48.         return ret;  
  49.     }  

[java] view plain copy
  1.     virtual int verifyChallenge(uint32_t uid, uint64_t challenge,  
  2.             const uint8_t *enrolled_password_handle, uint32_t enrolled_password_handle_length,  
  3.             const uint8_t *provided_password, uint32_t provided_password_length,  
  4.             uint8_t **auth_token, uint32_t *auth_token_length, bool *request_reenroll) {  
  5.         IPCThreadState* ipc = IPCThreadState::self();  
  6.         ...  
  7.   
  8. +       ALOGI("verifyChallenge start. ");if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) {  
  9.             return PERMISSION_DENIED;  
  10.         }  
  11.   
  12.         // can't verify if we're missing either paramif ((enrolled_password_handle_length | provided_password_length) == 0)  
  13.             return -EINVAL;  
  14.   
  15.         int ret;  
  16.         if (device) {  
  17.             const gatekeeper::password_handle_t *handle =  
  18.                     reinterpret_cast<const gatekeeper::password_handle_t *>(enrolled_password_handle);  
  19.             // handle version 0 does not have hardware backed flag, and thus cannot be upgraded to// a HAL if there was none beforeif (handle->version == 0 || handle->hardware_backed) {  
  20.   
  21. +               ALOGI("hardware gatekeeper verify begin. ");ret = device->verify(device, uid, challenge,  
  22.                     enrolled_password_handle, enrolled_password_handle_length,  
  23.                     provided_password, provided_password_length, auth_token, auth_token_length,  
  24.                     request_reenroll);  
  25.             } else {  
  26.                 // upgrade scenario, a HAL has been added to this device where there was none beforeSoftGateKeeperDevice soft_dev;  
  27.   
  28. +               ALOGI("software gatekeeper verify begin. ");ret = soft_dev.verify(uid, challenge,  
  29.                     enrolled_password_handle, enrolled_password_handle_length,  
  30.                     provided_password, provided_password_length, auth_token, auth_token_length,  
  31.                     request_reenroll);  
  32.   
  33.                 if (ret == 0) {  
  34.                     // success! re-enroll with HAL  
  35.                     *request_reenroll = true;  
  36.                 }  
  37.             }  
  38.         } else {  
  39.   
  40. +           ALOGI("software gatekeeper verify begin. ");ret = soft_device->verify(uid, challenge,  
  41.                 enrolled_password_handle, enrolled_password_handle_length,  
  42.                 provided_password, provided_password_length, auth_token, auth_token_length,  
  43.                 request_reenroll);  
  44.         }  
  45.   
  46. +       ALOGI("gatekeeper verify end. ret: %d", ret);  
  47.   
  48.   
  49.         ...  
  50.         return ret;  
  51.     }  

通过上面的log,应该可以初步定位无法解锁和解锁慢的问题,然后在依据结果具体问题具体分析。

(3)如何通过log知道创建的是software还是hardware gatekeeper?

答: 在开机时候创建gatekeeper daemon的时候通过/system/core/gatekeeperd/gatekeeperd.cpp中的main函数启动daemon,

会创建GateKeeperProxy实例, 在GateKeeperProxy的构造函数,会决定创建的是software还是hardware gatekeeper:

[java] view plain copy
  1. GateKeeperProxy() {  
  2.     int ret = hw_get_module_by_class(GATEKEEPER_HARDWARE_MODULE_ID, NULL, &module);//尝试获取HW gatekpper  
  3.     device = NULL;  
  4.   
  5.     if (ret < 0) {  
  6.         ALOGW("falling back to software GateKeeper"); //如果有这条log出来,就表示用的是sw。否则就是hwsoft_device.reset(new SoftGateKeeperDevice());//使用sw gatekeeper  
  7.     } else {  
  8.         ret = gatekeeper_open(module, &device); //尝试打开hw gatekeeper  
  9.         if (ret < 0)  
  10.             LOG_ALWAYS_FATAL_IF(ret < 0"Unable to open GateKeeper HAL");  
  11.     }  
  12.   
  13.     if (mark_cold_boot()) {  
  14.         ALOGI("cold boot: clearing state");  
  15.         if (device != NULL && device->delete_all_users != NULL) {  
  16.             device->delete_all_users(device);  
  17.         }  
  18.     }  
  19. }  


原文地址: http://blog.csdn.net/yj934672573/article/details/54571704