天天看點

Android P 指紋 Framework

從Android的官方API可以查到,向上層提供接口的是FingerprintManager,它的代碼在路徑frameworks/base/core/java/android/hardware/fingerprint下。

/**
 * A class that coordinates access to the fingerprint hardware.
 * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting
 * authentication. In a world where devices may have different types of biometric authentication,
 * it's much more realistic to have a system-provided authentication dialog since the method may
 * vary by vendor/device.
 */
@Deprecated
@SystemService(Context.FINGERPRINT_SERVICE)
@RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
public class FingerprintManager implements BiometricFingerprintConstants
           

frameworks/base/core/java/android/hardware/fingerprint目錄下内容其實很少,一共隻有幾個檔案。

Android P 指紋 Framework

這裡除了FingerprintManager之外,就隻有Fingerprint一個類了,其他都是aidl檔案。

粗略的看了下Fingerprint類,它裡面的内容超級少,主要是包含了幾個成員變量,用來記錄指紋的資訊。

/**
 * Container for fingerprint metadata.
 * @hide
 */
public final class Fingerprint extends BiometricAuthenticator.BiometricIdentifier {
    private CharSequence mName;
    private int mGroupId;
    private int mFingerId;
    private long mDeviceId; // physical device this is associated with

    public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) {
        mName = name;
        mGroupId = groupId;
        mFingerId = fingerId;
        mDeviceId = deviceId;
    }
    //...
}
           

如果仔細看代碼的話,可以發現一個很神奇的東西,那個就Fingerprint類的所有成員都是private的,并且沒有提供任何public的set方法!

這個就厲害了,因為有做過指紋部分的朋友一定記得指紋提供一個rename的接口。沒有public的set方法,那它又是怎麼實作rename接口的呢?

帶着問題看源碼!

rename方法在Manager中的實作如下:

/**
 * Renames the given fingerprint template
 * @param fpId the fingerprint id
 * @param userId the user who this fingerprint belongs to
 * @param newName the new name
 *
 * @hide
 */
@RequiresPermission(MANAGE_FINGERPRINT)
public void rename(int fpId, int userId, String newName) {
        // Renames the given fpId
        if (mService != null) {
            try {
                mService.rename(fpId, userId, newName);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } else {
            Slog.w(TAG, "rename(): Service not connected!");
        }
}
           

這裡先直接找到Manager的服務類:FingerprintService

指紋服務的相關代碼在frameworks\base\services\core\java\com\android\server\fingerprint下。

/**
 * A service to manage multiple clients that want to access the fingerprint HAL API.
 * The service is responsible for maintaining a list of clients and dispatching all
 * fingerprint-related events.
 *
 * @hide
 */
public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient
           

看一下它裡面的rename是在内部類FingerprintServiceWrapper中實作的,具體如下:

@Override // Binder call
public void rename(final int fingerId, final int groupId, final String name) {
    checkPermission(MANAGE_FINGERPRINT);
    if (!isCurrentUserOrProfile(groupId)) {
        return;
    }
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
                    groupId, name);
        }
    }
}
           

找到同檔案夾下FingerprintUtils類,這個是工具類,裡面維護了一組FingerprintsUserState,具體得繼續看FingerprintsUserState;

FingerprintsUserState中維護了一組Fingerprint,下面具體看下rename操作:

@GuardedBy("this")
private final ArrayList<Fingerprint> mFingerprints = new ArrayList<Fingerprint>();
//...

public void renameFingerprint(int fingerId, CharSequence name) {
    synchronized (this) {
        for (int i = 0; i < mFingerprints.size(); i++) {
            if (mFingerprints.get(i).getFingerId() == fingerId) {
                Fingerprint old = mFingerprints.get(i);
                mFingerprints.set(i, new Fingerprint(name, old.getGroupId(), 
                        old.getFingerId(), old.getDeviceId()));
                scheduleWriteStateLocked();
                break;
            }
        }
    }
}
           

這裡可以看到,在rename的實作時,代碼直接霸氣的new一個Fingerprint對象,然後覆寫List中對應id的對象。

OK,以上隻是一個小小的流程。

下面看下FingerprintManager的主要API:

public void enroll(byte [] token, CancellationSignal cancel, int flags,
            int userId, EnrollmentCallback callback);
public void remove(Fingerprint fp, int userId, RemovalCallback callback);
public void rename(int fpId, int userId, String newName);
public List<Fingerprint> getEnrolledFingerprints();


//不是hide的方法
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler);
public boolean hasEnrolledFingerprints();
public boolean isHardwareDetected()
           

真正對三方開放的API隻有最下面的三個,分别用來授權、判斷是否錄入過指紋、判斷裝置是否支援指紋器件。

這裡面要特别提一下authenicate方法;

/**
     * Request authentication of a crypto object. This call warms up the fingerprint hardware
     * and starts scanning for a fingerprint. It terminates when
     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
     * which point the object is no longer valid. The operation can be canceled by using the
     * provided cancel object.
     *
     * @param crypto object associated with the call or null if none required.
     * @param cancel an object that can be used to cancel authentication
     * @param flags optional flags; should be 0
     * @param callback an object to receive authentication events
     * @param handler an optional handler to handle callback events
     *
     * @throws IllegalArgumentException if the crypto operation is not supported or is not backed
     *         by <a href="{@docRoot}training/articles/keystore.html" target="_blank" rel="external nofollow" >Android Keystore
     *         facility</a>.
     * @throws IllegalStateException if the crypto primitive is not initialized.
     * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
     * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(
     * BiometricPrompt.CryptoObject, CancellationSignal, Executor,
     * BiometricPrompt.AuthenticationCallback)}
     */
    @Deprecated
    @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
            int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {
        authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId());
    }
           

其中flags暫時沒用起來,直接設定為0。 

這裡稍微講下crypto objiect。它是的一個内部類。暫時支援三種類型對象。如下:

/**
     * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
     * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
     */
           

這個參數用于加密,保護指紋在使用過程中不被惡意軟體截獲和篡改。

Google的示例中用的是Cipher的加密對象。 

需要結束監聽的話,使用CancellationSignal對象的cancel方法即可。

上面提到過Manager裡面的API具體實作都是Service中。

Manager中儲存有Service的對象private IFingerprintService mService;

這對象看命名方式就可以大概猜到是個AIDL了;

/**
 * Communication channel from client to the fingerprint service.
 * @hide
 */
interface IFingerprintService
           

它是在Manager的構造函數作為參數傳入的,找到建立Manager的地方:

frameworks/base/core/java/android/app/SystemServiceRegistry.java

registerService(Context.FINGERPRINT_SERVICE, FingerprintManager.class,
        new CachedServiceFetcher<FingerprintManager>() {
    @Override
    public FingerprintManager createService(ContextImpl ctx) throws ServiceNotFoundException {
        final IBinder binder;
        if (ctx.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
            binder = ServiceManager.getServiceOrThrow(Context.FINGERPRINT_SERVICE);
        } else {
            binder = ServiceManager.getService(Context.FINGERPRINT_SERVICE);
        }
        IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
        return new FingerprintManager(ctx.getOuterContext(), service);
}});
           

從這裡看,關鍵字是Context.FINGERPRINT_SERVICE這個服務!

這時候,靈機一動看一眼FingerprintService(通過搜尋可以搜到FingerprintService),它的onStart方法中有釋出這個服務,釋出的是它的内部類FingerprintServiceWrapper,這裡就解釋了為什麼之前Manager裡面的rename方法最後會在FingerprintServiceWrapper被搜尋到。

@Override
public void onStart() {
    publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
    SystemServerInitThreadPool.get().submit(this::getFingerprintDaemon, TAG + ".onStart");
    listenForUserSwitches();
}
           

而FingerprintService本身是在frameworks/base/services/java/com/android/server/SystemServer.java中啟動的;

if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
    traceBeginAndSlog("StartFingerprintSensor");
    mSystemServiceManager.startService(FingerprintService.class);
    traceEnd();
}
           

 下面來看一下一個消息回報的AIDL:IFingerprintServiceReceiver;

/**
 * Communication channel from the FingerprintService back to FingerprintManager.
 * @hide
 */
oneway interface IFingerprintServiceReceiver {
    void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
    void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
    void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId);
    void onAuthenticationFailed(long deviceId);
    void onError(long deviceId, int error, int vendorCode);
    void onRemoved(long deviceId, int fingerId, int groupId, int remaining);
    void onEnumerated(long deviceId, int fingerId, int groupId, int remaining);
}
           

它的執行個體在Manager中;

private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub
           

作為參數被傳遞給Service,實作消息回報機制。

如果仔細看下FingerprintService所在的檔案夾,除了之前提到過的FingerprintService、FingerprintUtils和FingerprintsUserState以外就隻剩下大量和ClientMonitor 相關的類了;

/**
 * Abstract base class for keeping track and dispatching events from fingerprint HAL to the
 * the current client.  Subclasses are responsible for coordinating the interaction with
 * fingerprint HAL for the specific action (e.g. authenticate, enroll, enumerate, etc.).
 */
public abstract class ClientMonitor implements IBinder.DeathRecipient
           

它的子類包括AuthenticationClient、EnrollClient、EnumerateClient、InternalEnumerateClient、InternalRemovalClient和RemovalClient。

它們是真正負責和更下層的HAL層互動的類。

HAL層有關的内容這裡暫不讨論。

這樣的話,大概的一組流程被整理出來,FingerprintManager内部持有FingerprintService内部類FingerprintServiceWrapper的AIDL,FingerprintManager的API都是調用FingerprintServiceWrapper提供的接口實作的,同時通過參數實作IFingerprintServiceReceiver消息回傳。

Android P 指紋 Framework

這裡還有一點可以提一下,那就是指紋授權時的震動;

  1. frameworks/base/services/core/java/com/android/server/fingerprint/AuthenticationClient.java中會在授權成功或失敗後調用vibrateSuccess()和vibrateError()方法實作不同的震動效果
  2. frameworks/base/services/core/java/com/android/server/fingerprint/ClientMonitor.java有vibrateSuccess()和vibrateError()兩個方法的具體實作
  3. 在ClientMonitor中可以看到frameworks\base\core\java\android\os\VibrationEffect.java是真正實作震動的類
  4. 可以通過用VibrationEffect的createOneShot或createWaveform方法建立想要的震動效果