312 lines
11 KiB
C++
312 lines
11 KiB
C++
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "fingerprintd"
|
|
|
|
#include <android/hardware/biometrics/fingerprint/2.1/types.h>
|
|
#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
|
|
#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
|
|
#include <binder/IServiceManager.h>
|
|
#include <keystore/IKeystoreService.h>
|
|
#include <keystore/keystore.h> // for error codes
|
|
#include <utils/Log.h>
|
|
|
|
#include "FingerprintDaemonProxy.h"
|
|
|
|
namespace android {
|
|
|
|
using hardware::hidl_string;
|
|
using hardware::Return;
|
|
using hardware::biometrics::fingerprint::V2_1::FingerprintMsg;
|
|
using hardware::biometrics::fingerprint::V2_1::RequestStatus;
|
|
using hardware::biometrics::fingerprint::V2_1::FingerprintError;
|
|
using hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
|
|
using Type = hardware::biometrics::fingerprint::V2_1::FingerprintMsgType;
|
|
using IBiometricsFingerprint = hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
|
|
|
|
FingerprintDaemonProxy* FingerprintDaemonProxy::sInstance = nullptr;
|
|
static sp<IBiometricsFingerprint> gBFP = nullptr;
|
|
static sp<IBiometricsFingerprintClientCallback> gClientCallback = nullptr;
|
|
|
|
template <typename E>
|
|
constexpr typename std::underlying_type<E>::type to_native(E e) {
|
|
return static_cast<typename std::underlying_type<E>::type>(e);
|
|
}
|
|
|
|
const ssize_t hw_auth_token_size = 69;
|
|
|
|
namespace hardware {
|
|
|
|
class BiometricsFingerprintClientCallback : public IBiometricsFingerprintClientCallback {
|
|
public:
|
|
BiometricsFingerprintClientCallback() {};
|
|
virtual ~BiometricsFingerprintClientCallback() = default;
|
|
Return<void> notify(const FingerprintMsg& msg) {
|
|
FingerprintDaemonProxy::hal_notify_callback(msg);
|
|
return Void();
|
|
}
|
|
};
|
|
|
|
IBiometricsFingerprintClientCallback* HIDL_FETCH_IBiometricsFingerprintClientCallback(const char* /* name */) {
|
|
return new BiometricsFingerprintClientCallback();
|
|
}
|
|
|
|
} // namespace hardware
|
|
|
|
FingerprintDaemonProxy::FingerprintDaemonProxy() : mCallback(nullptr) {
|
|
|
|
}
|
|
|
|
FingerprintDaemonProxy::~FingerprintDaemonProxy() {
|
|
closeHal();
|
|
}
|
|
|
|
void FingerprintDaemonProxy::hal_notify_callback(const hardware::biometrics::fingerprint::V2_1::FingerprintMsg &msg) {
|
|
FingerprintDaemonProxy* instance = FingerprintDaemonProxy::getInstance();
|
|
const sp<IFingerprintDaemonCallback> callback = instance->mCallback;
|
|
if (callback == nullptr) {
|
|
ALOGE("Invalid callback object");
|
|
return;
|
|
}
|
|
switch (msg.type) {
|
|
case Type::ERROR:
|
|
ALOGD("onError(%d)", msg.data.error);
|
|
callback->onError(0, to_native(msg.data.error));
|
|
break;
|
|
case Type::ACQUIRED:
|
|
ALOGD("onAcquired(%d)", msg.data.acquired.acquiredInfo);
|
|
callback->onAcquired(0, to_native(msg.data.acquired.acquiredInfo));
|
|
break;
|
|
case Type::AUTHENTICATED:
|
|
ALOGD("onAuthenticated(fid=%d, gid=%d)",
|
|
msg.data.authenticated.finger.fid,
|
|
msg.data.authenticated.finger.gid);
|
|
if (msg.data.authenticated.finger.fid != 0) {
|
|
const uint8_t* hat = reinterpret_cast<const uint8_t *>(&msg.data.authenticated.hat);
|
|
instance->notifyKeystore(hat, sizeof(msg.data.authenticated.hat));
|
|
}
|
|
callback->onAuthenticated(0,
|
|
msg.data.authenticated.finger.fid,
|
|
msg.data.authenticated.finger.gid);
|
|
break;
|
|
case Type::TEMPLATE_ENROLLING:
|
|
ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)",
|
|
msg.data.enroll.finger.fid,
|
|
msg.data.enroll.finger.gid,
|
|
msg.data.enroll.samplesRemaining);
|
|
callback->onEnrollResult(0,
|
|
msg.data.enroll.finger.fid,
|
|
msg.data.enroll.finger.gid,
|
|
msg.data.enroll.samplesRemaining);
|
|
break;
|
|
case Type::TEMPLATE_REMOVED:
|
|
ALOGD("onRemove(fid=%d, gid=%d)",
|
|
msg.data.removed.finger.fid,
|
|
msg.data.removed.finger.gid);
|
|
callback->onRemoved(0,
|
|
msg.data.removed.finger.fid,
|
|
msg.data.removed.finger.gid);
|
|
break;
|
|
case Type::TEMPLATE_ENUMERATING:
|
|
ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)",
|
|
msg.data.enumerated.finger.fid,
|
|
msg.data.enumerated.finger.gid,
|
|
msg.data.enumerated.remainingTemplates);
|
|
callback->onEnumerate(0,
|
|
msg.data.enumerated.finger.fid,
|
|
msg.data.enumerated.finger.gid,
|
|
msg.data.enumerated.remainingTemplates);
|
|
break;
|
|
default:
|
|
ALOGE("invalid msg type: %d", msg.type);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void FingerprintDaemonProxy::notifyKeystore(const uint8_t *auth_token, const size_t auth_token_length) {
|
|
if (auth_token != nullptr && auth_token_length > 0) {
|
|
// TODO: cache service?
|
|
sp < IServiceManager > sm = defaultServiceManager();
|
|
sp < IBinder > binder = sm->getService(String16("android.security.keystore"));
|
|
sp < IKeystoreService > service = interface_cast < IKeystoreService > (binder);
|
|
if (service != nullptr) {
|
|
status_t ret = service->addAuthToken(auth_token, auth_token_length);
|
|
if (ret != ResponseCode::NO_ERROR) {
|
|
ALOGE("Falure sending auth token to KeyStore: %d", ret);
|
|
}
|
|
} else {
|
|
ALOGE("Unable to communicate with KeyStore");
|
|
}
|
|
}
|
|
}
|
|
|
|
void FingerprintDaemonProxy::init(const sp<IFingerprintDaemonCallback>& callback) {
|
|
if (mCallback != nullptr && IInterface::asBinder(callback) != IInterface::asBinder(mCallback)) {
|
|
IInterface::asBinder(mCallback)->unlinkToDeath(this);
|
|
}
|
|
IInterface::asBinder(callback)->linkToDeath(this);
|
|
mCallback = callback;
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::enroll(const uint8_t* token, ssize_t tokenSize, int32_t groupId,
|
|
int32_t timeout) {
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "enroll(gid=%d, timeout=%d)\n", groupId, timeout);
|
|
if (tokenSize != hw_auth_token_size) {
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "enroll() : invalid token size %zd, expected %zd\n", tokenSize, hw_auth_token_size);
|
|
return -1;
|
|
}
|
|
|
|
hardware::hidl_array<uint8_t, hw_auth_token_size> hat(token);
|
|
Return<RequestStatus> ret = gBFP->enroll(hat, groupId, timeout);
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
uint64_t FingerprintDaemonProxy::preEnroll() {
|
|
return gBFP->preEnroll();
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::postEnroll() {
|
|
Return<RequestStatus> ret = gBFP->postEnroll();
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::stopEnrollment() {
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "stopEnrollment()\n");
|
|
Return<RequestStatus> ret = gBFP->cancel();
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::authenticate(uint64_t sessionId, uint32_t groupId) {
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "authenticate(sid=%" PRId64 ", gid=%d)\n", sessionId, groupId);
|
|
Return<RequestStatus> ret = gBFP->authenticate(sessionId, groupId);
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::stopAuthentication() {
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "stopAuthentication()\n");
|
|
Return<RequestStatus> ret = gBFP->cancel();
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::remove(int32_t fingerId, int32_t groupId) {
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "remove(fid=%d, gid=%d)\n", fingerId, groupId);
|
|
Return<RequestStatus> ret = gBFP->remove(groupId, fingerId);
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::enumerate() {
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "enumerate()\n");
|
|
Return<RequestStatus> ret = gBFP->enumerate();
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
uint64_t FingerprintDaemonProxy::getAuthenticatorId() {
|
|
return gBFP->getAuthenticatorId();
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::setActiveGroup(int32_t groupId, const uint8_t* path,
|
|
ssize_t pathlen) {
|
|
if (pathlen >= PATH_MAX || pathlen <= 0) {
|
|
ALOGE("Bad path length: %zd", pathlen);
|
|
return -1;
|
|
}
|
|
hidl_string pathname;
|
|
pathname.setToExternal(reinterpret_cast<const char*>(path), pathlen);
|
|
ALOG(LOG_VERBOSE, LOG_TAG, "setActiveGroup(%d, %s, %zu)", groupId, pathname.c_str(), pathlen);
|
|
Return<RequestStatus> ret = gBFP->setActiveGroup(groupId, pathname);
|
|
if (!ret.getStatus().isOk()) {
|
|
ALOGE("Unknown transport error");
|
|
return -1;
|
|
}
|
|
|
|
RequestStatus status = ret;
|
|
return to_native(status);
|
|
}
|
|
|
|
int64_t FingerprintDaemonProxy::openHal() {
|
|
if (gBFP == nullptr) {
|
|
// TODO(b/31632518)
|
|
gBFP = IBiometricsFingerprint::getService("fingerprint");
|
|
if(gBFP == nullptr) {
|
|
ALOGE("Can't get service fingerprint");
|
|
return 0;
|
|
}
|
|
}
|
|
gClientCallback = hardware::HIDL_FETCH_IBiometricsFingerprintClientCallback(nullptr);
|
|
gBFP->setNotify(gClientCallback);
|
|
return reinterpret_cast<int64_t>(gBFP.get());
|
|
}
|
|
|
|
int32_t FingerprintDaemonProxy::closeHal() {
|
|
// Obsolete, return 0 for compatibility reasons.
|
|
return 0;
|
|
}
|
|
|
|
void FingerprintDaemonProxy::binderDied(const wp<IBinder>& who) {
|
|
ALOGD("binder died");
|
|
int err;
|
|
if (0 != (err = closeHal())) {
|
|
ALOGE("Can't close fingerprint device, error: %d", err);
|
|
}
|
|
if (IInterface::asBinder(mCallback) == who) {
|
|
mCallback = nullptr;
|
|
}
|
|
}
|
|
|
|
} // namespace android
|