指纹解锁基本原理

启动指纹监听:  用户打开指纹识别开关时,开机初始化,唤醒,睡眠,都回调到 updateFingerprintListeningState更新是否打开指纹监听。

   private void updateFingerprintListeningState() {

       boolean shouldListenForFingerprint = shouldListenForFingerprint();

       if (mFingerprintDetectionRunning && !shouldListenForFingerprint){

           stopListeningForFingerprint();

       } else if (!mFingerprintDetectionRunning && shouldListenForFingerprint){

           startListeningForFingerprint();

       }

    }

startListeningForFingerprint 中调用mFpm.authenticate(null,mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);实现指纹监听扫描。

 

FingerprintManager 通过跨进程调用实现:它实际就调到了FingerprintService内部类 FingerprintServiceWrapper中的方法。如下:(关于mService为什么是FingerprintService后面有说明)

 mService.authenticate(mToken, sessionId, userId, mServiceReceiver,flags,

                   mContext.getOpPackageName());

FingerprintService.java 内部类FingerprintServiceWrapper的方法:

    @Override // Binder call

       public void authenticate(final IBinder token, final long opId, final intgroupId,

                finalIFingerprintServiceReceiver receiver, final int flags,

                final String opPackageName) {

           if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {

                Slog.w(TAG, "Can'tauthenticate non-current user");

                return;

           }

           if (!canUseFingerprint(opPackageName)) {

                Slog.w(TAG, "Calling notgranted permission to use fingerprint");

                return;

           }

 

           // Group ID is arbitrarily set to parent profile user ID. It justrepresents

           // the default fingerprints for the user.

           final int effectiveGroupId = getEffectiveUserId(groupId);

 

           final boolean restricted = isRestricted();

           mHandler.post(new Runnable() {

                @Override

                public void run() {

                    startAuthentication(token, opId,effectiveGroupId, receiver, flags, restricted);

                }

           });

       }

 

关于mService为什么是FingerprintService后面有说明如下:

 

  FingerprintService.java在其中注册了FINGERPRINT_SERVICE服务,方便系统直接通过

SystemServer中调用FingerprintService的start方法最后调到publishBinderService来绑定服务

   mSystemServiceManager.startService(FingerprintService.class);—》publishBinderService

ServiceManager.getService进行获取:

  publishBinderService(Context.FINGERPRINT_SERVICE, newFingerprintServiceWrapper());

(publishBinderService 的实际实现systemService.java的ServiceManager.addService(name, service, allowIsolated);)

 

注册初始化:FingerprintManager,这样fingerprintManager就可以以代理的方式调用FingprintService

      SystemServiceRegistry.java中:

       registerService(Context.FINGERPRINT_SERVICE, FingerprintManager.class,

                newCachedServiceFetcher<FingerprintManager>() {

           @Override

           public FingerprintManager createService(ContextImpl ctx) {

                IBinder binder =ServiceManager.getService(Context.FINGERPRINT_SERVICE);

                IFingerprintService service =IFingerprintService.Stub.asInterface(binder);

                return newFingerprintManager(ctx.getOuterContext(), service);

           }});

 

 

mService.authenticate最后调到了:   final int result = daemon.authenticate(opId,groupId);

这个也同样是跨进程调用,被调用的进程是fingerd (C++书写的守护进程)。

 

 

fingerd进程分析:

      入口为fingerprintd.cpp文件中的main函数:

 android::sp<android::FingerprintDaemonProxy>proxy =

           android::FingerprintDaemonProxy::getInstance();

   android::status_t ret = serviceManager->addService(

           android::FingerprintDaemonProxy::descriptor, proxy);

添加服务到serviceManager中这样framework代码就可以跨进程拿到这个服务也是aidl原理。不过这个是实现了c++aidl.

     那我们就开始看它核心(FingerprintDaemonProxy)proxy 到底做了些什么?

其中包括:

FingerprintDaemonProxy::authenticate  指纹认证实际调用的地方:daemon.authenticate就调用fingerd这个函数;

 

FingerprintDaemonProxy::init初始化:如进行初始化一个回调等

         在FingerprintService就有用到:(注册一个回调给fingerd)      

       public IFingerprintDaemongetFingerprintDaemon() {

       if (mDaemon == null) {

           mDaemon =IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD));

           if (mDaemon != null) {

                try {

                   mDaemon.asBinder().linkToDeath(this, 0);

                   mDaemon.init(mDaemonCallback);

                    mHalDeviceId =mDaemon.openHal();

 

 

FingerprintDaemonProxy::hal_notify_callback  注册到device驱动中:如FingerprintDaemonProxy::openHal() —》err =mDevice->set_notify(mDevice, hal_notify_callback);  如:驱动进行指纹的识别动作,根据不同的返回码调用hal_notify_callback这个回调,这个回调最后回调到mDaemon.init(mDaemonCallback);初始化进去的mDaemonCallback(即框架上层的回调)

 

如authenticate  操作经过指纹汇顶驱动进行匹配后,会回调执行到以下函数。 最后通过callback->onAuthenticated回调反馈给上层处理。

 

   caseFINGERPRINT_AUTHENTICATED:

            ALOGD("onAuthenticated(fid=%d, gid=%d)",

                    msg->data.authenticated.finger.fid,

                    msg->data.authenticated.finger.gid);

            if (msg->data.authenticated.finger.fid!= 0) {

                const uint8_t* hat = reinterpret_cast<const uint8_t*>(&msg->data.authenticated.hat);

                instance->notifyKeystore(hat,sizeof(msg->data.authenticated.hat));

            }

            callback->onAuthenticated(device,

                    msg->data.authenticated.finger.fid,

                    msg->data.authenticated.finger.gid);

           break;

 

 

那么上层的callback->onAuthenticated是怎么处理的呢?

callback实际上是FingerprintService.java中的IFingerprintDaemonCallbackmDaemonCallback = new IFingerprintDaemonCallback.Stub(){

      @Override

       public void onAuthenticated(long deviceId, int fingerId, int groupId) {

           dispatchAuthenticated(deviceId, fingerId, groupId);

       }

}

———>最后调到:receiver.onAuthenticationSucceeded(mHalDeviceId,fp);

   

receiver实际是:KeyguardUpdateMonitor.java

 

privateFingerprintManager.AuthenticationCallback mAuthenticationCallback

           = new AuthenticationCallback() {

 

       @Override

       public void onAuthenticationSucceeded(AuthenticationResult result) {

           handleFingerprintAuthenticated();

       }

 

   };

 

handleFingerprintAuthenticated 会调到KeyguardUpdateMonitorCallback,而其中的一个KeyguardUpdateMonitorCallback实际就是KeyguardViewMediator.onFingerprintAuthenticated这个函数就实现了解锁功能:

KeyguardUpdateMonitorCallback cb =mCallbacks.get(i).get();

 cb.onFingerprintAuthenticated(userId,wakeAndUnlocking);

**************

   public void onFingerprintAuthenticated(int userId, booleanwakeAndUnlocking) {

                if (wakeAndUnlocking &&mShowing && unlockingWithFingerprintAllowed) {

                    mWakeAndUnlocking = true;

                   mStatusBarKeyguardViewManager.setWakeAndUnlocking();

                    keyguardDone(true, true);

                } else if (mShowing &&mDeviceInteractive) {

                    if (wakeAndUnlocking) {

                       mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();

                    }

                   mStatusBarKeyguardViewManager.animateCollapsePanels(

                           FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);

                }

           }

       };

***************

KeyguardViewMediator.onFingerprintAuthenticated这个函数就实现了解锁功能:

    黑屏指纹解锁调用:keyguardDone(true,true);

    亮屏指纹解锁调用:mStatusBarKeyguardViewManager.animateCollapsePanels(

                           FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);

 

先讲解:亮屏指纹解锁调用的过程:

   1:状态栏的一些处理 :如: PanelView

   2:执行mBar.makeExpandedInvisible(); 实现解锁

     1)添加mHideExpandedRunnable到sPendingRunnables中

     2)postAnimationCallback调用执行sPendingRunnables

 private Runnable mHideExpandedRunnable = new Runnable() {

       @Override

       public void run() {

           mBar.makeExpandedInvisible();

       }

   };

上面的mHideExpandedRunnable是由下面函数进行调用的。

 

  private staticvoid postAnimationCallback() {

       sChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,sAnimationCallbackRunnable,

               null);

    }

 

其中有对于调用的控制最后又doFrame 做每一帧的时候根据条件调用doCallbacks函数,这里会调用到上列的mHideExpandedRunnable。

 

 

 

执行mBar.makeExpandedInvisible();实现解锁的解锁过程:

1)最终它也是调用mViewMediatorCallback.keyguardDone(true);实现的解锁

    通过:

makeExpandedInvisible  –》StatusBarKeyguarViewManager.dismiss(booleanauthenticated)–> showBouncer—>KeyguardBouncer.show(..)—>mKeyguardView.dismiss(authenticated)

 

mKeyguardView.dismiss(authenticated)就是实现解锁的关键方法:

   KeyguardHostView.dismiss() –>KeyguardSecurityContainer. showNextSecurityScreenOrFinish(….)

 

showNextSecurityScreenOrFinish最终会调到mSecurityCallback.finish();

而mSecurityCallback是KeyguardHostView.即最终调了KeyguardHostView. finish()

        if (mViewMediatorCallback != null) {

           if (deferKeyguardDone) {

               mViewMediatorCallback.keyguardDonePending();

           } else {

               mViewMediatorCallback.keyguardDone(true);

           }

       }

 

***************************************************************************

mViewMediatorCallback实际是定义在KeyguardViewMediator.java中

ViewMediatorCallback mViewMediatorCallback= new ViewMediatorCallback() {

 

       public void userActivity() {

           KeyguardViewMediator.this.userActivity();

       }

 

       public void keyguardDone(boolean authenticated) {

           if (!mKeyguardDonePending) {

                KeyguardViewMediator.this.keyguardDone(authenticated,true);

           }

       }

 

这里终于调到了KeyguardViewMediator.keyguardDone.

 

 

 

 

 

那我们从现在开始论述KeyguardViewMediator.keyguardDone.的解锁过程:

keyguardDone 实际调用解锁handleHide

  最终它会跑到如下的代码进入框架进行解锁流程:

 

    private final RunnablemKeyguardGoingAwayRunnable = new Runnable() {

        @Override

        public void run() {

            try {

               mStatusBarKeyguardViewManager.keyguardGoingAway();

 

                // Don't actually hide theKeyguard at the moment, wait for window

                // manager until it tells usit's safe to do so with

                // startKeyguardExitAnimation.

               ActivityManagerNative.getDefault().keyguardGoingAway(

                        mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()

                                ||mWakeAndUnlocking,

                       mStatusBarKeyguardViewManager.isGoingToNotificationShade());

            } catch (RemoteException e) {

                Log.e(TAG, "Error whilecalling WindowManager", e);

            }

        }

    };

 其中mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock()

                                ||mWakeAndUnlocking,

可以控制解锁进桌面是否播放动画。keyguardGoingAway先是通过ActivityManagerService调到WindowManagerService的keyguardGoingAway

设置了mAnimator属性后直接进入requestTraversalLocked();进行窗口的变化。

performLayoutAndPlaceSurfacesLocked–》performLayoutAndPlaceSurfacesLockedLoop–》performLayoutAndPlaceSurfacesLockedInner—》

这个过程有很多窗口的layout 等最后跑到scheduleAnimationLocked();函数中。最后进入WindowAnimator的窗口动画中。

 

scheduleAnimationLocked到animateLocked   的过程:

mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);其实它是通过Choreographer机制最后调用mAnimationFrameCallback——Choreographer通过利用Vsync机制执行执行Choreographer.dnFrame从而通过doCallbacks(Choreographer.CALLBACK_ANIMATION,frameTimeNanos);调用到了mAnimationFrameCallback

 

 

 

下面说一下animateLocked主要干了些什么?  

window动画分为两种:窗口中的动画,Activity切换个动画。

 

   1)updateWindowsLocked

这里需要指出的变量是:   

// Currentlyrunning animation.

    boolean mAnimating;

  if (mAnimating) {

               mService.scheduleAnimationLocked();

            }

它是判断当前是否在有动画在执行:判断规则比较严格,如果窗口还有更多动画,或有Activity动画它都会反复调用scheduleAnimationLocked进行多次执行,这是为了保证窗口的画面的正确性。有时我们能通过判断这个变量拿到窗口动画执行的总时间。

下面通过代码分析认证这个:

updateWindowsLocked(displayId);

就是通过这个进行条件判断:winAnimator.stepAnimationLocked(mCurrentTime);里面就是通过判断

窗口是否还有更多动画需要执行,或有Activity动画来返回true或false来赋值mAnimating

 

updateWallpaperLocked(displayId)

updateWallpaperLocked同样也会进行判断:winAnimator.mAnimating来赋值mAnimating

如果最终mAnimating是True它会再次执行scheduleAnimationLocked

  if (mAnimating) {

               mService.scheduleAnimationLocked();

            }

 

      最终这个过程通过mPolicy.startKeyguardExitAnimation(mCurrentTime, 0 /*duration */);跑出框架。mPolicy实际是PhoneWindowManager对象。即最终调用了

   public void startKeyguardExitAnimation(longstartTime, long fadeoutDuration) {

mKeyguardDelegate.startKeyguardExitAnimation(startTime,fadeoutDuration);

        }

    }

然后调到mKeyguardService.startKeyguardExitAnimation(startTime,fadeoutDuration);

即调到了KeyguardViewMediator的handleStartKeyguardExitAnimation

很多时候我们可以认为如果调到handleStartKeyguardExitAnimation那么解锁就完成了,但严格上也不能说它完成了(因为这时候其实窗口还是在变化中,我们无法确定窗口时候已经全部绘画完成),所以这个函数很多时候用来处理解锁完成后的一些事情。

 

  2)updateWallpaperLocked

3:窗口动画的呈现:WinAnimator.prepareSurfaceLocked

   1)  computeShownFrameLocked(); 计算需要呈现的动画

   2)赋值动画变化矩阵,透明度,Z轴到mSurfaceControl中

     

                   mSurfaceAlpha = mShownAlpha;

                   mSurfaceControl.setAlpha(mShownAlpha);

                   mSurfaceLayer = mAnimLayer;

                   mSurfaceControl.setLayer(mAnimLayer);

                   mSurfaceControl.setMatrix(

                            mDsDx * w.mHScale,mDtDx * w.mVScale,

                            mDsDy * w.mHScale,mDtDy * w.mVScale);

  3)通过surfacefinger绘制surface画布纹理从而实现动画。

     showSurfaceRobustlyLocked.mSurfaceControl.show();

 

 

再说一下Choreographer机制:

 

 

最后会执行到    调用输入窗口,其他窗口,窗口动画的回调函数

  mFrameInfo.markInputHandlingStart();

           doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

 

            mFrameInfo.markAnimationsStart();

           doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

 

           mFrameInfo.markPerformTraversalsStart();

           doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

 

            doCallbacks(Choreographer.CALLBACK_COMMIT,frameTimeNanos);

如下面所列都用到这个机制:

    1:窗口动画:mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);

    2:View的添加然后窗口创建:

如:应用通过addView来添加布局View

  1.   //3 选定了窗口修饰布局文件 ,添加至DecorView对象里,并且指定mcontentParent  
  2.     View in = mLayoutInflater.inflate(layoutResource, null);  
  3.     decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); 

它的工作原理是:

ViewRootImp是用户与WMS沟通的桥梁,通过DectorView .addView

ViewRootImp.setView—-> ViewRootImp. requestLayout–>ViewRootImp. scheduleTraversals最后会执行到:

   mChoreographer.postCallback(

                       Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

 

最后执行到mTraversalRunnable这个回调函数:

mTraversalRunnable做了些什么呢?

  1) performMeasure   View进行大小计算

  2) performLayout      View进行布局

2) performDraw();  进行绘画

 

 

代码过程如下:

doTraversal()–>performTraversals —》performMeasure  

                

                                      —》performLayout     

                                      —》performDraw

performDraw的过程比较有意思:

 

  performDraw –》draw(fullRedrawNeeded);

draw(fullRedrawNeeded);主要作用

  1:  surface = mSurface;拿到计算后的刚才通过performMeasure  ,performLayout    过程后的surface纹理画布

  2:drawSoftware(surface, mAttachInfo, xOffset,yOffset, scalingRequired, dirty)通过mView.draw(canvas)遍历绘制DectorView, surface.unlockCanvasAndPost(canvas);sufaceFinger绘制这个suface.

 3:判断是否有动画,如果有,走动画的过程。

if(animating) {

            mFullRedrawNeeded = true;

            scheduleTraversals();

        }

Published by

风君子

独自遨游何稽首 揭天掀地慰生平