Android7.0指纹服务FingerprintService实例介绍
指纹服务是Android系统中一个较为简单的服务(相比于AMS,WMS等),也比较独立,功能上包括几点
- 指纹的录入与删除
- 指纹认证
- 指纹的安全策略(错误次数判定)
和其他的systemservice一样,应用程序通过FingerprintManager实现与FingerprintService的通信,除了上面所说的功能之外,FingerprintManager提供了一些别的的接口,重要的接口都会要求系统级别的权限,并且也不是公开的api(指纹的录入,删除,重命名,重置错误计数等)
/** *Obtainthelistofenrolledfingerprintstemplates. *@returnlistofcurrentfingerprintitems * *@hide */ @RequiresPermission(USE_FINGERPRINT) publicListgetEnrolledFingerprints(intuserId){ if(mService!=null)try{ returnmService.getEnrolledFingerprints(userId,mContext.getOpPackageName()); }catch(RemoteExceptione){ throwe.rethrowFromSystemServer(); } returnnull; } /** *@hide */ @RequiresPermission(allOf={ USE_FINGERPRINT, INTERACT_ACROSS_USERS}) publicbooleanhasEnrolledFingerprints(intuserId){ if(mService!=null)try{ returnmService.hasEnrolledFingerprints(userId,mContext.getOpPackageName()); }catch(RemoteExceptione){ throwe.rethrowFromSystemServer(); } returnfalse; } /** *Determineiffingerprinthardwareispresentandfunctional. * *@returntrueifhardwareispresentandfunctional,falseotherwise. */ @RequiresPermission(USE_FINGERPRINT) publicbooleanisHardwareDetected(){ if(mService!=null){ try{ longdeviceId=0;/*TODO:plumbhardwareidtoFPMS*/ returnmService.isHardwareDetected(deviceId,mContext.getOpPackageName()); }catch(RemoteExceptione){ throwe.rethrowFromSystemServer(); } }else{ Log.w(TAG,"isFingerprintHardwareDetected():Servicenotconnected!"); } returnfalse; }
FingerprintService的启动过程
FingerprintService在systemserver中创建并初始化,当检测到手机支持指纹功能的时候就会启动这个service
...
if(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)){
mSystemServiceManager.startService(FingerprintService.class);
}
...
FingerprintService在初始化后会建立和HAL层的通信,即连接到fingerprintd,拿到用于通信的IFingerprintDaemon对象(binder)
publicvoidonStart(){
publishBinderService(Context.FINGERPRINT_SERVICE,newFingerprintServiceWrapper());
IFingerprintDaemondaemon=getFingerprintDaemon();
listenForUserSwitches();
}
publicIFingerprintDaemongetFingerprintDaemon(){
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();
if(mHalDeviceId!=0){
updateActiveGroup(ActivityManager.getCurrentUser(),null);
}else{
Slog.w(TAG,"FailedtoopenFingerprintHAL!");
MetricsLogger.count(mContext,"fingerprintd_openhal_error",1);
mDaemon=null;
}
}catch(RemoteExceptione){
Slog.e(TAG,"FailedtoopenfingeprintdHAL",e);
mDaemon=null;//tryagainlater!
}
}else{
Slog.w(TAG,"fingerprintservicenotavailable");
}
}
returnmDaemon;
}
本质上来说,除去安全相关的策略外,指纹的功能是依赖硬件实现的,FingerprintService也只是充当了frameworkjava层与native层的消息传递者罢了,所以指纹的识别,录入和监听都是向fingerprintd发送命令和获取相应的结果
指纹监听认证过程
以指纹认证为例,介绍这一过程,录入和删除的过程和认证类似,不重复描述
FingerprintManager
publicvoidauthenticate(@NullableCryptoObjectcrypto,@NullableCancellationSignalcancel,
intflags,@NonNullAuthenticationCallbackcallback,Handlerhandler,intuserId){
if(callback==null){
thrownewIllegalArgumentException("Mustsupplyanauthenticationcallback");
}
if(cancel!=null){
if(cancel.isCanceled()){
Log.w(TAG,"authenticationalreadycanceled");
return;
}else{
cancel.setOnCancelListener(newOnAuthenticationCancelListener(crypto));
}
}
if(mService!=null)try{
useHandler(handler);
mAuthenticationCallback=callback;
mCryptoObject=crypto;
longsessionId=crypto!=null?crypto.getOpId():0;
mService.authenticate(mToken,sessionId,userId,mServiceReceiver,flags,
mContext.getOpPackageName());
}catch(RemoteExceptione){
Log.w(TAG,"Remoteexceptionwhileauthenticating:",e);
if(callback!=null){
//Thoughthismaynotbeahardwareissue,itwillcauseappstogiveuportry
//againlater.
callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
}
}
}
可以看到,最终仍然是向FingerprintService发送消息,但是开启指纹认证的函数传入了两个比较重要的参数,一个是CancellationSignal对象,用于取消指纹认证,另一个是指纹认证的回调对象AuthenticationCallback
publicstaticabstractclassAuthenticationCallback{
publicvoidonAuthenticationError(interrorCode,CharSequenceerrString){}
publicvoidonAuthenticationHelp(inthelpCode,CharSequencehelpString){}
publicvoidonAuthenticationSucceeded(AuthenticationResultresult){}
publicvoidonAuthenticationFailed(){}
publicvoidonAuthenticationAcquired(intacquireInfo){}
};
看函数名称也能知道其功能,他们分别代表了指纹认证时的回调结果(成功,失败,检测到指纹,认证异常等),参数包含了具体的信息,这些信息在FingerprintManager中都有对应的常量定义,有兴趣可以查看代码
FingerprintService
publicvoidauthenticate(finalIBindertoken,finallongopId,finalintgroupId,
finalIFingerprintServiceReceiverreceiver,finalintflags,
finalStringopPackageName){
finalintcallingUid=Binder.getCallingUid();
finalintcallingUserId=UserHandle.getCallingUserId();
finalintpid=Binder.getCallingPid();
finalbooleanrestricted=isRestricted();
mHandler.post(newRunnable(){
@Override
publicvoidrun(){
if(!canUseFingerprint(opPackageName,true/*foregroundOnly*/,
callingUid,pid)){
if(DEBUG)Slog.v(TAG,"authenticate():reject"+opPackageName);
return;
}
MetricsLogger.histogram(mContext,"fingerprint_token",opId!=0L?1:0);
//Getperformancestatsobjectforthisuser.
HashMappmap
=(opId==0)?mPerformanceMap:mCryptoPerformanceMap;
PerformanceStatsstats=pmap.get(mCurrentUserId);
if(stats==null){
stats=newPerformanceStats();
pmap.put(mCurrentUserId,stats);
}
mPerformanceStats=stats;
startAuthentication(token,opId,callingUserId,groupId,receiver,
flags,restricted,opPackageName);
}
});
}
前面会有对包名,userid以及应用进程是否在在前台的检查,继续看
privatevoidstartAuthentication(IBindertoken,longopId,intcallingUserId,intgroupId,
IFingerprintServiceReceiverreceiver,intflags,booleanrestricted,
StringopPackageName){
updateActiveGroup(groupId,opPackageName);
if(DEBUG)Slog.v(TAG,"startAuthentication("+opPackageName+")");
AuthenticationClientclient=newAuthenticationClient(getContext(),mHalDeviceId,token,
receiver,mCurrentUserId,groupId,opId,restricted,opPackageName){
@Override
publicbooleanhandleFailedAttempt(){
mFailedAttempts++;
if(mFailedAttempts==MAX_FAILED_ATTEMPTS){
mPerformanceStats.lockout++;
}
if(inLockoutMode()){
//Failingmultipletimeswillcontinuetopushoutthelockouttime.
scheduleLockoutReset();
returntrue;
}
returnfalse;
}
@Override
publicvoidresetFailedAttempts(){
FingerprintService.this.resetFailedAttempts();
}
@Override
publicvoidnotifyUserActivity(){
FingerprintService.this.userActivity();
}
@Override
publicIFingerprintDaemongetFingerprintDaemon(){
returnFingerprintService.this.getFingerprintDaemon();
}
};
if(inLockoutMode()){
Slog.v(TAG,"Inlockoutmode;disallowingauthentication");
//Don'tbotherstartingtheclient.Justsendtheerrormessage.
if(!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)){
Slog.w(TAG,"Cannotsendtimeoutmessagetoclient");
}
return;
}
startClient(client,true/*initiatedByClient*/);
}
AuthenticationClient继承自ClientMonitor,用于处理指纹认证相关的功能事务,ClientMonitor的其他子类如RemovalMonior,EnrollMonitor也是如此,ClientMonitor会直接与fingerprintd通信,其核心是调用其start()或stop()方法,
对于AuthenticationClient而言
privatevoidstartClient(ClientMonitornewClient,booleaninitiatedByClient){
ClientMonitorcurrentClient=mCurrentClient;
if(currentClient!=null){
if(DEBUG)Slog.v(TAG,"requeststopcurrentclient"+currentClient.getOwnerString());
currentClient.stop(initiatedByClient);
mPendingClient=newClient;
mHandler.removeCallbacks(mResetClientState);
mHandler.postDelayed(mResetClientState,CANCEL_TIMEOUT_LIMIT);
}elseif(newClient!=null){
mCurrentClient=newClient;
if(DEBUG)Slog.v(TAG,"startingclient"
+newClient.getClass().getSuperclass().getSimpleName()
+"("+newClient.getOwnerString()+")"
+",initiatedByClient="+initiatedByClient+")");
newClient.start();
}
}
publicintstart(){
IFingerprintDaemondaemon=getFingerprintDaemon();
if(daemon==null){
Slog.w(TAG,"startauthentication:nofingeprintd!");
returnERROR_ESRCH;
}
try{
finalintresult=daemon.authenticate(mOpId,getGroupId());
if(result!=0){
Slog.w(TAG,"startAuthenticationfailed,result="+result);
MetricsLogger.histogram(getContext(),"fingeprintd_auth_start_error",result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
returnresult;
}
if(DEBUG)Slog.w(TAG,"client"+getOwnerString()+"isauthenticating...");
}catch(RemoteExceptione){
Slog.e(TAG,"startAuthenticationfailed",e);
returnERROR_ESRCH;
}
return0;//success
}
向底层发送认证命令后就只需要等待认证结果就可以了,前面我们说到在初始化的时候会建立与fingerprintd的通信,其核心是下面这行代码
mDaemon.init(mDaemonCallback);
mDaemonCallback是一个binder对象,接受来自底层的结果,然后通过FingerprintService和FingerManager一层层把结果发送到应用程序中去。
8.0的一些变化
8.0上的fingerprintd变化很大,甚至都不叫fingerprintd了,当然这是native层的东西,这里不讨论,对于FingerprintService而言,一个显著的变化是安全策略的调整
- 8.0之前,指纹只能错误5次,达到5次时会禁止指纹认证,同时开启30秒倒计时,等待结束后重置错误计数,继续认证
- 8.0之后,依然是每错误5次就会倒计时30秒,然而30秒结束后错误计数并不会被清空,8.0上加入了最大20次的限制,累计错误20次之后就无法使用指纹认证功能了,只能用密码的方式才能重置错误计数
privatestaticfinalintMAX_FAILED_ATTEMPTS_LOCKOUT_TIMED=5;
privatestaticfinalintMAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT=20;
privateintgetLockoutMode(){
if(mFailedAttempts>=MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT){
returnAuthenticationClient.LOCKOUT_PERMANENT;
}elseif(mFailedAttempts>0&&mTimedLockoutCleared==false&&
(mFailedAttempts%MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED==0)){
returnAuthenticationClient.LOCKOUT_TIMED;
}
returnAuthenticationClient.LOCKOUT_NONE;
}
总结
以上所述是小编给大家介绍的Android7.0指纹服务FingerprintService实例介绍,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!