当前位置: 首页 > 编程笔记 >

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

邹桐
2023-03-14
本文向大家介绍Android7.0指纹服务FingerprintService实例介绍,包括了Android7.0指纹服务FingerprintService实例介绍的使用技巧和注意事项,需要的朋友参考一下

指纹服务是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实例介绍,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!

 类似资料:
  • 4.6 服务的指纹识别 为了确保有一个成功的渗透测试,必须需要知道目标系统中服务的指纹信息。服务指纹信息包括服务端口、服务名和版本等。在Kali中,可以使用Nmap和Amap工具识别指纹信息。本节将介绍使用Nmap和Amap工具的使用。 4.6.1 使用Nmap工具识别服务指纹信息 使用Nmap工具查看192.168.41.136服务上正在运行的端口。执行命令如下所示: 从输出的信息中可以查看到目

  • 我有android应用程序,后端是。NET网站。 我已经注册了我的用户使用Hampster Fingkey扫描仪的指纹,并将他们的指纹存储在服务器中。 有没有什么方法可以让我获取指纹并将数据发送到服务器,然后在我的SQL数据库中与Android进行匹配? 这可能吗?

  • 本文向大家介绍IOS 指纹识别详解及实例代码,包括了IOS 指纹识别详解及实例代码的使用技巧和注意事项,需要的朋友参考一下 IOS 指纹识别,这里整理下项目中用的知识。 IOS 指纹识别现在,在要求安全与效率兼得的时候,普通密码已不能满足我们的要求,指纹识别就这样诞生了。 每个人都有自己专属的指纹,在需要支付等输入密码的地方,我们只需轻轻一按即可,避免了输入密码的繁琐步骤,更加安全,而且妈妈再也不

  • Xiaomi Cloud-ML简介 小米云深度学习服务,简称Xiaomi Cloud-ML,是小米生态云针对机器学习优化的高性能、分布式云服务。 开发者可以在云端使用GPU训练模型,秒级启动分布式训练任务,兼容TensorFlow等深度学习框架,也可以一键部署训练好的模型,或者创建基于GPU的开发环境,提供模型开发、训练、调优、测试、部署和预测一站式解决方案。云深度学习服务还开放了API、SDK、

  • 我遇到了一种奇怪的情况,第一次需要连接到SFTP服务器,但似乎找不到访问该服务器已知主机条目的方法。如果我说: 但显然这让你容易受到中间人的攻击。因此,我尝试连接: 我会收到各种各样的错误信息。最近的一次是: 我运气不好吗?我是不是应该绕过钥匙检查?

  • 本文向大家介绍vue.js指令和组件详细介绍及实例,包括了vue.js指令和组件详细介绍及实例的使用技巧和注意事项,需要的朋友参考一下 大家好,本文给各位做一下vue.js一个最基本的概念介绍。 vue.js 指令 这个例子我们会得到,v-text所在的div元素的内部插入了'Hello Vue!'这段字符串,那么我们为什么会产生这样一个结果呢,我们来分析一下: 这一步的意思是,实例化的这个Vue