首页 > 系统 > Android > 正文

Android7.0指纹服务FingerprintService实例介绍

2019-10-22 18:17:29
字体:
来源:转载
供稿:网友

指纹服务是Android系统中一个较为简单的服务(相比于AMS,WMS等),也比较独立,功能上包括几点

  • 指纹的录入与删除
  • 指纹认证
  • 指纹的安全策略(错误次数判定)

和其他的system service 一样,应用程序通过FingerprintManager实现与FingerprintService的通信,除了上面所说的功能之外,FingerprintManager提供了一些别的的接口,重要的接口都会要求系统级别的权限,并且也不是公开的api(指纹的录入,删除,重命名,重置错误计数等)   

 /**  * Obtain the list of enrolled fingerprints templates.  * @return list of current fingerprint items  *  * @hide  */ @RequiresPermission(USE_FINGERPRINT) public List<Fingerprint> getEnrolledFingerprints(int userId) {  if (mService != null) try {   return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());  } catch (RemoteException e) {   throw e.rethrowFromSystemServer();  }  return null; } /**  * @hide  */ @RequiresPermission(allOf = {   USE_FINGERPRINT,   INTERACT_ACROSS_USERS}) public boolean hasEnrolledFingerprints(int userId) {  if (mService != null) try {   return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());  } catch (RemoteException e) {   throw e.rethrowFromSystemServer();  }  return false; } /**  * Determine if fingerprint hardware is present and functional.  *  * @return true if hardware is present and functional, false otherwise.  */ @RequiresPermission(USE_FINGERPRINT) public boolean isHardwareDetected() {  if (mService != null) {   try {    long deviceId = 0; /* TODO: plumb hardware id to FPMS */    return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());   } catch (RemoteException e) {    throw e.rethrowFromSystemServer();   }  } else {   Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");  }  return false; }

FingerprintService的启动过程

FingerprintService在system server中创建并初始化,当检测到手机支持指纹功能的时候就会启动这个service

...if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {  mSystemServiceManager.startService(FingerprintService.class); }...

FingerprintService在初始化后会建立和HAL层的通信,即连接到fingerprintd,拿到用于通信的IFingerprintDaemon对象(binder)

public void onStart() {  publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());  IFingerprintDaemon daemon = getFingerprintDaemon();  listenForUserSwitches(); }public IFingerprintDaemon getFingerprintDaemon() {  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, "Failed to open Fingerprint HAL!");      MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);      mDaemon = null;     }    } catch (RemoteException e) {     Slog.e(TAG, "Failed to open fingeprintd HAL", e);     mDaemon = null; // try again later!    }   } else {    Slog.w(TAG, "fingerprint service not available");   }  }  return mDaemon; }

本质上来说,除去安全相关的策略外,指纹的功能是依赖硬件实现的,FingerprintService也只是充当了framework java层与native层的消息传递者罢了,所以指纹的识别,录入和监听都是向fingerprintd发送命令和获取相应的结果

指纹监听认证过程

以指纹认证为例,介绍这一过程,录入和删除的过程和认证类似,不重复描述

FingerprintManager

public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,   int flags, @NonNull AuthenticationCallback callback, Handler handler, int userId) {  if (callback == null) {   throw new IllegalArgumentException("Must supply an authentication callback");  }  if (cancel != null) {   if (cancel.isCanceled()) {    Log.w(TAG, "authentication already canceled");    return;   } else {    cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));   }  }  if (mService != null) try {   useHandler(handler);   mAuthenticationCallback = callback;   mCryptoObject = crypto;   long sessionId = crypto != null ? crypto.getOpId() : 0;   mService.authenticate(mToken, sessionId, userId, mServiceReceiver, flags,     mContext.getOpPackageName());  } catch (RemoteException e) {   Log.w(TAG, "Remote exception while authenticating: ", e);   if (callback != null) {    // Though this may not be a hardware issue, it will cause apps to give up or try    // again later.    callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,      getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));   }  } }

可以看到,最终仍然是向FingerprintService发送消息,但是开启指纹认证的函数传入了两个比较重要的参数,一个是CancellationSignal对象,用于取消指纹认证,另一个是指纹认证的回调对象AuthenticationCallback

public static abstract class AuthenticationCallback {  public void onAuthenticationError(int errorCode, CharSequence errString) { }  public void onAuthenticationHelp(int helpCode, CharSequence helpString) { }  public void onAuthenticationSucceeded(AuthenticationResult result) { }  public void onAuthenticationFailed() { }  public void onAuthenticationAcquired(int acquireInfo) {} };

看函数名称也能知道其功能,他们分别代表了指纹认证时的回调结果(成功,失败,检测到指纹,认证异常等),参数包含了具体的信息,这些信息在FingerprintManager中都有对应的常量定义,有兴趣可以查看代码

FingerprintService

public void authenticate(final IBinder token, final long opId, final int groupId,    final IFingerprintServiceReceiver receiver, final int flags,    final String opPackageName) {   final int callingUid = Binder.getCallingUid();   final int callingUserId = UserHandle.getCallingUserId();   final int pid = Binder.getCallingPid();   final boolean restricted = isRestricted();   mHandler.post(new Runnable() {    @Override    public void run() {     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);     // Get performance stats object for this user.     HashMap<Integer, PerformanceStats> pmap       = (opId == 0) ? mPerformanceMap : mCryptoPerformanceMap;     PerformanceStats stats = pmap.get(mCurrentUserId);     if (stats == null) {      stats = new PerformanceStats();      pmap.put(mCurrentUserId, stats);     }     mPerformanceStats = stats;     startAuthentication(token, opId, callingUserId, groupId, receiver,       flags, restricted, opPackageName);    }   });  }

前面会有对包名,userid以及应用进程是否在在前台的检查,继续看

private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,    IFingerprintServiceReceiver receiver, int flags, boolean restricted,    String opPackageName) {  updateActiveGroup(groupId, opPackageName);  if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");  AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,    receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {   @Override   public boolean handleFailedAttempt() {    mFailedAttempts++;    if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {     mPerformanceStats.lockout++;    }    if (inLockoutMode()) {     // Failing multiple times will continue to push out the lockout time.     scheduleLockoutReset();     return true;    }    return false;   }   @Override   public void resetFailedAttempts() {    FingerprintService.this.resetFailedAttempts();   }   @Override   public void notifyUserActivity() {    FingerprintService.this.userActivity();   }   @Override   public IFingerprintDaemon getFingerprintDaemon() {    return FingerprintService.this.getFingerprintDaemon();   }  };  if (inLockoutMode()) {   Slog.v(TAG, "In lockout mode; disallowing authentication");   // Don't bother starting the client. Just send the error message.   if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {    Slog.w(TAG, "Cannot send timeout message to client");   }   return;  }  startClient(client, true /* initiatedByClient */); }

AuthenticationClient继承自ClientMonitor,用于处理指纹认证相关的功能事务,ClientMonitor的其他子类如RemovalMonior,EnrollMonitor也是如此,ClientMonitor会直接与fingerprintd通信,其核心是调用其start()或stop()方法,
对于AuthenticationClient而言

private void startClient(ClientMonitor newClient, boolean initiatedByClient) {  ClientMonitor currentClient = mCurrentClient;  if (currentClient != null) {   if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString());   currentClient.stop(initiatedByClient);   mPendingClient = newClient;   mHandler.removeCallbacks(mResetClientState);   mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);  } else if (newClient != null) {   mCurrentClient = newClient;   if (DEBUG) Slog.v(TAG, "starting client "     + newClient.getClass().getSuperclass().getSimpleName()     + "(" + newClient.getOwnerString() + ")"     + ", initiatedByClient = " + initiatedByClient + ")");   newClient.start();  } }public int start() {  IFingerprintDaemon daemon = getFingerprintDaemon();  if (daemon == null) {   Slog.w(TAG, "start authentication: no fingeprintd!");   return ERROR_ESRCH;  }  try {   final int result = daemon.authenticate(mOpId, getGroupId());   if (result != 0) {    Slog.w(TAG, "startAuthentication failed, result=" + result);    MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);    onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);    return result;   }   if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating...");  } catch (RemoteException e) {   Slog.e(TAG, "startAuthentication failed", e);   return ERROR_ESRCH;  }  return 0; // 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次之后就无法使用指纹认证功能了,只能用密码的方式才能重置错误计数
private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;private int getLockoutMode() {  if (mFailedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {   return AuthenticationClient.LOCKOUT_PERMANENT;  } else if (mFailedAttempts > 0 && mTimedLockoutCleared == false &&    (mFailedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {   return AuthenticationClient.LOCKOUT_TIMED;  }  return AuthenticationClient.LOCKOUT_NONE; }

总结

以上所述是小编给大家介绍的Android7.0指纹服务FingerprintService实例介绍,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对VEVB武林网网站的支持!


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表