Android8.0 Fingerprint指纹启动流程详细分析

Android8.0的指纹流程,相较于Android6.0和Android7.0来说,是一个版本更新。
Android系统对于fingerprint的支持,大体分为如下三种情况:
1、Android5.0及以前,没有集成指纹fingerprint。
2、Android6.0和Android7.0,集成了指纹fingerprint,但是6和7差异不大。
3、Android8.0和Android9.0相对于7.0来说,HAL层有所改动,还增加了hwbinder、HIDL等新特性。
博主预计Android8.0上面改善的这套fingerprint指纹架构,至少会维持4个Android大版本,比如Android8-Android11。

本文,就以Android8.0的指纹启动流程来进行解析,详细的说明指纹是如何启动的, 其内容基本也可以适用Android8.0以后的系统。

开机自启动系统服务,在文件:
/frameworks/base/services/java/com/android/server/SystemServer.java

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

可以看到,系统服务里面判断了是否系统里面集成了指纹功能,Android8.0是默认有的,所以会startService(FingerprintService)
所以我们进入到如下文件的startService方法:
/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

120    public void startService(@NonNull final SystemService service) {
121        // Register it.
122        mServices.add(service);
123        // Start it.
124        long time = SystemClock.elapsedRealtime();
125        try {
126            service.onStart();
127        } catch (RuntimeException ex) {
128            throw new RuntimeException("Failed to start service " + service.getClass().getName()
129                    + ": onStart threw an exception", ex);
130        }
131        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
132    }

如上,我们看到一个关键的方法:service.onStart(),这个意思就是FingerprintService.java里面的onStart将被调用。
所以我们进入到如下文件:
/frameworks/base/services/core/java/com/android/server/fingerprint/FingerprintService.java

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

我们看到,首先是创建了对象FingerprintServiceWrapper,这是一个很关键的对象,如下是部分截图:
Android8.0 Fingerprint指纹启动流程详细分析_第1张图片
我们可以看到,其是继承自IFingerprintService,并且里面的函数都写了“Binder call”,这也侧面反映了, 这是binder通信的接口,其实这一块并不是Android8.0才有的,而是Android6.0的时候,就已经差不多是这也了。
这里的binder是连接哪里和FingerprintService呢?答案是FingerprintManager.java。
如下图是IFingerprintService.aidl的部分截图:
Android8.0 Fingerprint指纹启动流程详细分析_第2张图片
是FingerprintManager.java通过AIDL,binder通信,和FingerprintService.java进行了通信。
举个例子:比如系统设置APP里面拿到了FingerprintManager,然后往FingerprintManager下发了注册或是识别的命令,这些命令就是通过AIDL传递到了FingerprintService里面了。

继续回到前面的FingerprintService,再来看如下流程:

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

上面还有一个操作是调用this::getFingerprintDaemon,这是FingerprintService和HAL层进行通信了。

public synchronized IBiometricsFingerprint getFingerprintDaemon() {
        if (mDaemon == null) {
            Slog.v(TAG, "mDaemon was null, reconnect to fingerprint");
            try {
                mDaemon = IBiometricsFingerprint.getService();
            } catch (java.util.NoSuchElementException e) {
                // Service doesn't exist or cannot be opened. Logged below.
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to get biometric interface", e);
            }
            if (mDaemon == null) {
                Slog.w(TAG, "fingerprint HIDL not available");
                return null;
            }

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

            try {
                mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to open fingerprint HAL", e);
                mDaemon = null; // try again later!
            }

            if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
            if (mHalDeviceId != 0) {
                loadAuthenticatorIds();
                updateActiveGroup(ActivityManager.getCurrentUser(), null);
                doFingerprintCleanupForUser(ActivityManager.getCurrentUser());
            } else {
                Slog.w(TAG, "Failed to open Fingerprint HAL!");
                MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
                mDaemon = null;
            }
        }
        return mDaemon;
    }

首先,如下的语句,是去拿这个IBiometricsFingerprint服务,那这个服务是在哪呢,又是如何启动的呢?

mDaemon = IBiometricsFingerprint.getService();

让我们进入到如下的路径:
/hardware/interfaces/biometrics/fingerprint/2.1/default/[email protected]

service vendor.fps_hal /vendor/bin/hw/[email protected]
    # "class hal" causes a race condition on some devices due to files created
    # in /data. As a workaround, postpone startup until later in boot once
    # /data is mounted.
    class late_start
    user system
    group system input
    writepid /dev/cpuset/system-background/tasks

我们可以看到,如上是启动了一个@2.1-service,那这个服务里面是什么呢?
我们查看刚刚上面路径的Android.bp可以找到答案:

cc_binary {
    name: "[email protected]",
    defaults: ["hidl_defaults"],
    init_rc: ["[email protected]"],
    vendor: true,
    relative_install_path: "hw",
    srcs: [
        "BiometricsFingerprint.cpp",
        "service.cpp",
    ],

    shared_libs: [
        "libcutils",
        "liblog",
        "libhidlbase",
        "libhidltransport",
        "libhardware",
        "libutils",
        "[email protected]",
    ],

}

我们可以看到两个源文件:service.cpp以及BiometricsFingerprint.cpp。
我们进入到service.cpp里面:

int main() {
    android::sp bio = BiometricsFingerprint::getInstance();

    configureRpcThreadpool(1, true /*callerWillJoin*/);

    if (bio != nullptr) {
        if (::android::OK != bio->registerAsService()) {
            return 1;
        }
    } else {
        ALOGE("Can't create instance of BiometricsFingerprint, nullptr");
    }

    joinRpcThreadpool();

    return 0; // should never get here
}

如上我们可以清晰的看到,是将bio注册为了服务,这个服务是通过getInstance()得到的,bio是一个IBiometricsFingerprint类型的sp指针。
让我们继续回到FingerprintService里面,如下所示:

			try {
                mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to open fingerprint HAL", e);
                mDaemon = null; // try again later!
            }

我们可以看到,这里的mDaemon就是刚刚提到的IBiometricsFingerprint类型服务了,这也能解释为啥能拿到这个服务,是由于前面的rc自启动了这个服务,而服务service.cpp里面是注册好了IBiometricsFingerprint的。
那如下又该如何解释呢?

mDaemon.setNotify(mDaemonCallback);

我们可以将mDaemon看成是IBiometricsFingerprint类的对象。那这样是调用对象的成员函数。但是这个对象并不是在进程FingerprintService.java里面的呀,似乎看起来就像调用本地接口一样,你可能想到了,对的,这里又是binder这个IPC进程间通信了。
通信的双方分别是:
/frameworks/base/services/core/java/com/android/server/fingerprint/FingerprintService.java
/hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
那FingerprintManager和FingerprintService进行binder通信,有IFingerprintService.aidl的AIDL语言,那这里是否有类似的呢?
有的!!这就是Android8.0新引入的binder接口了,/dev/hwbinder了,使用的语言是HIDL,后缀名是.hal文件。
文件在哪呢?
/hardware/interfaces/biometrics/fingerprint/2.1/IBiometricsFingerprint.hal
/hardware/interfaces/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.hal
我们查看一下IBiometricsFingerprint.hal里面的部分内容:

package [email protected];

import IBiometricsFingerprintClientCallback;

interface IBiometricsFingerprint {
  /**
   * Set notification callback:
   * Registers a user function that must receive notifications from the HAL
   * This call must block if the HAL state machine is in busy state until HAL
   * leaves the busy state.
   *
   * @return deviceId is a unique handle for this fingerprint device
   */
  @callflow(next={"setActiveGroup"})
  @entry
  setNotify(IBiometricsFingerprintClientCallback clientCallback)
      generates (uint64_t deviceId);

如上可以看到,是有setNotify接口的,所以我们FingerprintService.java就是这样通过hwbinder也就是新的HIDL语言与我们的HAL层也就是BiometricsFingerprint.cpp通信了。
让我们以C/S的模型来理解就是:
FingerprintService.java充当client,知道接口说明,利用HIDL binder可以直接调用本地接口一样与其他进程进行通信。
BiometricsFingerprint.cpp充当server,对接口进行实现。
让我们进入到文件BiometricsFingerprint.cpp进行查看:

Return BiometricsFingerprint::setNotify(
        const sp& clientCallback) {
    std::lock_guard lock(mClientCallbackMutex);
    mClientCallback = clientCallback;
    // This is here because HAL 2.1 doesn't have a way to propagate a
    // unique token for its driver. Subsequent versions should send a unique
    // token for each call to setNotify(). This is fine as long as there's only
    // one fingerprint device on the platform.
    return reinterpret_cast(mDevice);
}

果然是实现好了接口。

细心的小伙伴可能发现了,除了IBiometricsFingerprint.hal还有一个IBiometricsFingerprintClientCallback.hal东东,
这又是干嘛的,这就不得不提到指纹的一些基础流程了,
比如APP下发注册命令->FingerprintManager收到命令->FingerprintService收到命令->BiometricsFingerprint收到命令->Fingerprint.cpp收到命令->指纹CA收到命令->指纹TA收到命令->SPI采集数据\算法进行注册等
那以上是自顶向下的命令传递,那如果最底层的TA已经注册完毕了,如何让最顶的APP知悉呢,这就涉及到callback也就是回调了呀,不回调信息,不告诉上层,上层怎么会知道呢。
让我们再以C/S的思想来理解:
通信的双方分别是:
/frameworks/base/services/core/java/com/android/server/fingerprint/FingerprintService.java
/hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
FingerprintService.java需要是回调,它这次充当Server,用于处理底层传递过来的数据。
BiometricsFingerprint.cpp充当client,调用事先设置好的callBack接口,这个接口也就是在FingerprintService.java里面设置好的mDaemonCallback了。

mDaemon.setNotify(mDaemonCallback);

至此,HIDL涉及到的两个.hal我们就已经说完了。

让我们回到service.cpp的如下这句话:

int main() {
    android::sp bio = BiometricsFingerprint::getInstance();
}

刚刚只是说明了FingerprintService是如何能够拿到IBiometricsFingerprint服务的,但是我们还没有分析BiometricsFingerprint::getInstance()的具体操作细节,这是非常关键的一步:打开HAL接口!!!
我们进入到文件BiometricsFingerprint.cpp,查看如下:

IBiometricsFingerprint* BiometricsFingerprint::getInstance() {
    if (!sInstance) {
      sInstance = new BiometricsFingerprint();
    }
    return sInstance;
}

如上我们看到是构造了一个BiometricsFingerprint类,继续查看:

BiometricsFingerprint::BiometricsFingerprint() : mClientCallback(nullptr), mDevice(nullptr) {
    sInstance = this; // keep track of the most recent instance
    mDevice = openHal();
    if (!mDevice) {
        ALOGE("Can't open HAL module");
    }
}

这里我们可以看到,sInstance就是BiometricsFingerprint对象本身,而mDevice就是HAL里面的设备。
这里的openHal我们继续查看:

fingerprint_device_t* BiometricsFingerprint::openHal() {
    int err;
    const hw_module_t *hw_mdl = nullptr;
    ALOGD("Opening fingerprint hal library...");
    if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_mdl))) {
        ALOGE("Can't open fingerprint HW Module, error: %d", err);
        return nullptr;
    }

    if (hw_mdl == nullptr) {
        ALOGE("No valid fingerprint module");
        return nullptr;
    }

    fingerprint_module_t const *module =
        reinterpret_cast(hw_mdl);
    if (module->common.methods->open == nullptr) {
        ALOGE("No valid open method");
        return nullptr;
    }

    hw_device_t *device = nullptr;

    if (0 != (err = module->common.methods->open(hw_mdl, nullptr, &device))) {
        ALOGE("Can't open fingerprint methods, error: %d", err);
        return nullptr;
    }

    if (kVersion != device->version) {
        // enforce version on new devices because of [email protected] translation layer
        ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
        return nullptr;
    }

    fingerprint_device_t* fp_device =
        reinterpret_cast(device);

    if (0 != (err =
            fp_device->set_notify(fp_device, BiometricsFingerprint::notify))) {
        ALOGE("Can't register fingerprint module callback, error: %d", err);
        return nullptr;
    }

    return fp_device;
}

是通过查找模块FINGERPRINT_HARDWARE_MODULE_ID这个ID找到,然后调用里面的open方法得到设备。那这个FINGERPRINT_HARDWARE_MODULE_ID在哪呢?
让我们进入到如下文件:
/hardware/libhardware/modules/fingerprint/fingerprint.c
其里面有对应ID:

fingerprint_module_t HAL_MODULE_INFO_SYM = {
    .common = {
        .tag                = HARDWARE_MODULE_TAG,
        .module_api_version = FINGERPRINT_MODULE_API_VERSION_2_0,
        .hal_api_version    = HARDWARE_HAL_API_VERSION,
        .id                 = FINGERPRINT_HARDWARE_MODULE_ID,
        .name               = "Demo Fingerprint HAL",
        .author             = "The Android Open Source Project",
        .methods            = &fingerprint_module_methods,
    },
};

所以就找到这个文件了,里面定义了open方法:

static struct hw_module_methods_t fingerprint_module_methods = {
    .open = fingerprint_open,
};

我们进入到fingerprint_open里面:

static int fingerprint_open(const hw_module_t* module, const char __unused *id,
                            hw_device_t** device)
{
    if (device == NULL) {
        ALOGE("NULL device on open");
        return -EINVAL;
    }

    fingerprint_device_t *dev = malloc(sizeof(fingerprint_device_t));
    memset(dev, 0, sizeof(fingerprint_device_t));

    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = FINGERPRINT_MODULE_API_VERSION_2_0;
    dev->common.module = (struct hw_module_t*) module;
    dev->common.close = fingerprint_close;

    dev->pre_enroll = fingerprint_pre_enroll;
    dev->enroll = fingerprint_enroll;
    dev->get_authenticator_id = fingerprint_get_auth_id;
    dev->cancel = fingerprint_cancel;
    dev->remove = fingerprint_remove;
    dev->set_active_group = fingerprint_set_active_group;
    dev->authenticate = fingerprint_authenticate;
    dev->set_notify = set_notify_callback;
    dev->notify = NULL;

    *device = (hw_device_t*) dev;
    return 0;
}

可以看到这里创建好了设备,并且对注册、识别等接口都进行了定义。
所以我们可以知道,注册流程一般是如下这样:
FingerprintService.java->BiometricsFingerprint.cpp->fingerprint.c
我们进入到fingerprint.c的注册方法里面查看:

static int fingerprint_enroll(struct fingerprint_device __unused *dev,
                                const hw_auth_token_t __unused *hat,
                                uint32_t __unused gid,
                                uint32_t __unused timeout_sec) {
    return FINGERPRINT_ERROR;
}

可以看到,如上是直接返回错误,并没有任何实现,这是什么原因呢?
这是由于,这是需要指纹IC厂商自行实现的呀,指纹IC厂商需要在这里接入,创建自己的HAL层代码,并且CA代码,最终接入到TA代码,大概含义就是:
FingerprintService.java->BiometricsFingerprint.cpp->fingerprint.c->vendorHal.cpp->vendorCA.cpp--------TEE环境->TA.c

另外,我们在FingerprintService.java设置的Callback,大概传递流程会是如下:
FingerprintService.java->BiometricsFingerprint.cpp->fingerprint.c->vendorHal.cpp
比如我们进入到fingerprint.c里面的设置回调接口:

static int set_notify_callback(struct fingerprint_device *dev,
                                fingerprint_notify_t notify) {
    /* Decorate with locks */
    dev->notify = notify;
    return FINGERPRINT_ERROR;
}

而在FingerprintService.java里面会接收底层传递过来的回调信息:

private IBiometricsFingerprintClientCallback mDaemonCallback =
            new IBiometricsFingerprintClientCallback.Stub() {

        @Override
        public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
                final int remaining) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    handleEnrollResult(deviceId, fingerId, groupId, remaining);
                }
            });
        }

        @Override
        public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    handleAcquired(deviceId, acquiredInfo, vendorCode);
                }
            });
        }

        @Override
        public void onAuthenticated(final long deviceId, final int fingerId, final int groupId,
                ArrayList token) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    handleAuthenticated(deviceId, fingerId, groupId, token);
                }
            });
        }

比如识别的结果会进入到如下的文件:
/frameworks/base/services/core/java/com/android/server/fingerprint/AuthenticationClient.java

IFingerprintServiceReceiver receiver = getReceiver();
        if (receiver != null) {
            try {
                MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_AUTH,
                        authenticated);
                if (!authenticated) {
                    receiver.onAuthenticationFailed(getHalDeviceId());
                } else {
                    if (DEBUG) {
                        Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString()
                                + ", id=" + fingerId + ", gp=" + groupId + ")");
                    }
                    Fingerprint fp = !getIsRestricted()
                            ? new Fingerprint("" /* TODO */, groupId, fingerId, getHalDeviceId())
                            : null;
                    receiver.onAuthenticationSucceeded(getHalDeviceId(), fp, getTargetUserId());
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failed to notify Authenticated:", e);
                result = true; // client failed
            }
        } else {
            result = true; // client not listening
        }

比如识别成功,接收者都会收到onAuthenticationSucceeded消息,最终APP就会收到这个消息,最终就能解锁手机。

如果大家喜欢如上的流程分析,欢迎给我留言,我会抽空继续更新注册流程、识别流程等的具体分析。

你可能感兴趣的:(Android,Fingerprint)