Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6ad586a authored by Ilya Matyukhin's avatar Ilya Matyukhin Committed by Android (Google) Code Review
Browse files

Merge changes I3a908b0f,I582d44d5 into sc-dev

* changes:
  Implement the state machine
  Add move-only lambdas support
parents 42aedcc4 48ff8969
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -6,9 +6,11 @@ cc_binary {
    vintf_fragments: ["fingerprint-default.xml"],
    local_include_dirs: ["include"],
    srcs: [
        "main.cpp",
        "CancellationSignal.cpp",
        "Fingerprint.cpp",
        "Session.cpp",
        "WorkerThread.cpp",
        "main.cpp",
    ],
    shared_libs: [
        "libbase",
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.
 */

#include "CancellationSignal.h"

#include <android-base/logging.h>
#include <chrono>

namespace aidl::android::hardware::biometrics::fingerprint {

CancellationSignal::CancellationSignal(std::promise<void>&& cancellationPromise)
    : mCancellationPromise(std::move(cancellationPromise)) {}

ndk::ScopedAStatus CancellationSignal::cancel() {
    mCancellationPromise.set_value();
    return ndk::ScopedAStatus::ok();
}

bool shouldCancel(const std::future<void>& f) {
    CHECK(f.valid());
    return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}

}  // namespace aidl::android::hardware::biometrics::fingerprint
+13 −4
Original line number Diff line number Diff line
@@ -15,11 +15,12 @@
 */

#include "Fingerprint.h"

#include "Session.h"

namespace aidl::android::hardware::biometrics::fingerprint {
namespace {

constexpr size_t MAX_WORKER_QUEUE_SIZE = 5;
constexpr int SENSOR_ID = 1;
constexpr common::SensorStrength SENSOR_STRENGTH = common::SensorStrength::STRONG;
constexpr int MAX_ENROLLMENTS_PER_USER = 5;
@@ -32,7 +33,8 @@ constexpr char SERIAL_NUMBER[] = "00000001";

}  // namespace

Fingerprint::Fingerprint() {}
Fingerprint::Fingerprint()
    : mEngine(std::make_unique<FakeFingerprintEngine>()), mWorker(MAX_WORKER_QUEUE_SIZE) {}

ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
    std::vector<common::HardwareInfo> hardwareInfos = {
@@ -52,14 +54,21 @@ ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
ndk::ScopedAStatus Fingerprint::createSession(int32_t sensorId, int32_t userId,
                                              const std::shared_ptr<ISessionCallback>& cb,
                                              std::shared_ptr<ISession>* out) {
    *out = SharedRefBase::make<Session>(cb);
    auto sessionSp = mSession.lock();
    CHECK(sessionSp == nullptr || sessionSp->isClosed()) << "Open session already exists!";

    auto session = SharedRefBase::make<Session>(sensorId, userId, cb, mEngine.get(), &mWorker);
    mSession = session;
    *out = session;
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Fingerprint::reset() {
    // Crash. The system will start a fresh instance of the HAL.
    CHECK(false) << "Unable to reset. Crashing.";
    return ndk::ScopedAStatus::ok();
}

+162 −38
Original line number Diff line number Diff line
@@ -14,93 +14,216 @@
 * limitations under the License.
 */

#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
#include "Session.h"

#include <android-base/logging.h>

#include "Session.h"
#include "CancellationSignal.h"

namespace aidl::android::hardware::biometrics::fingerprint {

class CancellationSignal : public common::BnCancellationSignal {
  public:
    ndk::ScopedAStatus cancel() override { return ndk::ScopedAStatus::ok(); }
};
Session::Session(int sensorId, int userId, std::shared_ptr<ISessionCallback> cb,
                 FakeFingerprintEngine* engine, WorkerThread* worker)
    : mSensorId(sensorId),
      mUserId(userId),
      mCb(std::move(cb)),
      mEngine(engine),
      mWorker(worker),
      mScheduledState(SessionState::IDLING),
      mCurrentState(SessionState::IDLING) {
    CHECK_GE(mSensorId, 0);
    CHECK_GE(mUserId, 0);
    CHECK(mEngine);
    CHECK(mWorker);
    CHECK(mCb);
}

void Session::scheduleStateOrCrash(SessionState state) {
    CHECK(mScheduledState == SessionState::IDLING);
    CHECK(mCurrentState == SessionState::IDLING);
    mScheduledState = state;
}

Session::Session(std::shared_ptr<ISessionCallback> cb) : mCb(std::move(cb)) {}
void Session::enterStateOrCrash(int cookie, SessionState state) {
    CHECK(mScheduledState == state);
    mCurrentState = mScheduledState;
    mScheduledState = SessionState::IDLING;
    mCb->onStateChanged(cookie, mCurrentState);
}

void Session::enterIdling(int cookie) {
    mCurrentState = SessionState::IDLING;
    mCb->onStateChanged(cookie, mCurrentState);
}

bool Session::isClosed() {
    return mCurrentState == SessionState::CLOSED;
}

ndk::ScopedAStatus Session::generateChallenge(int32_t /*cookie*/, int32_t /*timeoutSec*/) {
ndk::ScopedAStatus Session::generateChallenge(int32_t cookie, int32_t timeoutSec) {
    LOG(INFO) << "generateChallenge";
    scheduleStateOrCrash(SessionState::GENERATING_CHALLENGE);

    mWorker->schedule(Callable::from([this, cookie, timeoutSec] {
        enterStateOrCrash(cookie, SessionState::GENERATING_CHALLENGE);
        mEngine->generateChallengeImpl(mCb.get(), timeoutSec);
        enterIdling(cookie);
    }));

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::revokeChallenge(int32_t /*cookie*/, int64_t /*challenge*/) {
ndk::ScopedAStatus Session::revokeChallenge(int32_t cookie, int64_t challenge) {
    LOG(INFO) << "revokeChallenge";
    scheduleStateOrCrash(SessionState::REVOKING_CHALLENGE);

    mWorker->schedule(Callable::from([this, cookie, challenge] {
        enterStateOrCrash(cookie, SessionState::REVOKING_CHALLENGE);
        mEngine->revokeChallengeImpl(mCb.get(), challenge);
        enterIdling(cookie);
    }));

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::enroll(int32_t /*cookie*/, const keymaster::HardwareAuthToken& /*hat*/,
                                   std::shared_ptr<common::ICancellationSignal>* /*out*/) {
ndk::ScopedAStatus Session::enroll(int32_t cookie, const keymaster::HardwareAuthToken& hat,
                                   std::shared_ptr<common::ICancellationSignal>* out) {
    LOG(INFO) << "enroll";
    scheduleStateOrCrash(SessionState::ENROLLING);

    std::promise<void> cancellationPromise;
    auto cancFuture = cancellationPromise.get_future();

    mWorker->schedule(Callable::from([this, cookie, hat, cancFuture = std::move(cancFuture)] {
        enterStateOrCrash(cookie, SessionState::ENROLLING);
        if (shouldCancel(cancFuture)) {
            mCb->onError(Error::CANCELED, 0 /* vendorCode */);
        } else {
            mEngine->enrollImpl(mCb.get(), hat);
        }
        enterIdling(cookie);
    }));

    *out = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::authenticate(int32_t /*cookie*/, int64_t /*keystoreOperationId*/,
ndk::ScopedAStatus Session::authenticate(int32_t cookie, int64_t operationId,
                                         std::shared_ptr<common::ICancellationSignal>* out) {
    LOG(INFO) << "authenticate";
    if (mCb) {
        mCb->onStateChanged(0, SessionState::AUTHENTICATING);
    scheduleStateOrCrash(SessionState::AUTHENTICATING);

    std::promise<void> cancPromise;
    auto cancFuture = cancPromise.get_future();

    mWorker->schedule(
            Callable::from([this, cookie, operationId, cancFuture = std::move(cancFuture)] {
                enterStateOrCrash(cookie, SessionState::AUTHENTICATING);
                if (shouldCancel(cancFuture)) {
                    mCb->onError(Error::CANCELED, 0 /* vendorCode */);
                } else {
                    mEngine->authenticateImpl(mCb.get(), operationId);
                }
    *out = SharedRefBase::make<CancellationSignal>();
                enterIdling(cookie);
            }));

    *out = SharedRefBase::make<CancellationSignal>(std::move(cancPromise));
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::detectInteraction(
        int32_t /*cookie*/, std::shared_ptr<common::ICancellationSignal>* /*out*/) {
ndk::ScopedAStatus Session::detectInteraction(int32_t cookie,
                                              std::shared_ptr<common::ICancellationSignal>* out) {
    LOG(INFO) << "detectInteraction";
    scheduleStateOrCrash(SessionState::DETECTING_INTERACTION);

    std::promise<void> cancellationPromise;
    auto cancFuture = cancellationPromise.get_future();

    mWorker->schedule(Callable::from([this, cookie, cancFuture = std::move(cancFuture)] {
        enterStateOrCrash(cookie, SessionState::DETECTING_INTERACTION);
        if (shouldCancel(cancFuture)) {
            mCb->onError(Error::CANCELED, 0 /* vendorCode */);
        } else {
            mEngine->detectInteractionImpl(mCb.get());
        }
        enterIdling(cookie);
    }));

    *out = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::enumerateEnrollments(int32_t /*cookie*/) {
ndk::ScopedAStatus Session::enumerateEnrollments(int32_t cookie) {
    LOG(INFO) << "enumerateEnrollments";
    if (mCb) {
        mCb->onStateChanged(0, SessionState::ENUMERATING_ENROLLMENTS);
        mCb->onEnrollmentsEnumerated(std::vector<int32_t>());
    }
    scheduleStateOrCrash(SessionState::ENUMERATING_ENROLLMENTS);

    mWorker->schedule(Callable::from([this, cookie] {
        enterStateOrCrash(cookie, SessionState::ENUMERATING_ENROLLMENTS);
        mEngine->enumerateEnrollmentsImpl(mCb.get());
        enterIdling(cookie);
    }));

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::removeEnrollments(int32_t /*cookie*/,
                                              const std::vector<int32_t>& /*enrollmentIds*/) {
ndk::ScopedAStatus Session::removeEnrollments(int32_t cookie,
                                              const std::vector<int32_t>& enrollmentIds) {
    LOG(INFO) << "removeEnrollments";
    if (mCb) {
        mCb->onStateChanged(0, SessionState::REMOVING_ENROLLMENTS);
        mCb->onEnrollmentsRemoved(std::vector<int32_t>());
    }
    scheduleStateOrCrash(SessionState::REMOVING_ENROLLMENTS);

    mWorker->schedule(Callable::from([this, cookie, enrollmentIds] {
        enterStateOrCrash(cookie, SessionState::REMOVING_ENROLLMENTS);
        mEngine->removeEnrollmentsImpl(mCb.get(), enrollmentIds);
        enterIdling(cookie);
    }));

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::getAuthenticatorId(int32_t /*cookie*/) {
ndk::ScopedAStatus Session::getAuthenticatorId(int32_t cookie) {
    LOG(INFO) << "getAuthenticatorId";
    if (mCb) {
        mCb->onStateChanged(0, SessionState::GETTING_AUTHENTICATOR_ID);
        mCb->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
    }
    scheduleStateOrCrash(SessionState::GETTING_AUTHENTICATOR_ID);

    mWorker->schedule(Callable::from([this, cookie] {
        enterStateOrCrash(cookie, SessionState::GETTING_AUTHENTICATOR_ID);
        mEngine->getAuthenticatorIdImpl(mCb.get());
        enterIdling(cookie);
    }));

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t /*cookie*/) {
ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t cookie) {
    LOG(INFO) << "invalidateAuthenticatorId";
    scheduleStateOrCrash(SessionState::INVALIDATING_AUTHENTICATOR_ID);

    mWorker->schedule(Callable::from([this, cookie] {
        enterStateOrCrash(cookie, SessionState::INVALIDATING_AUTHENTICATOR_ID);
        mEngine->invalidateAuthenticatorIdImpl(mCb.get());
        enterIdling(cookie);
    }));

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::resetLockout(int32_t /*cookie*/,
                                         const keymaster::HardwareAuthToken& /*hat*/) {
ndk::ScopedAStatus Session::resetLockout(int32_t cookie, const keymaster::HardwareAuthToken& hat) {
    LOG(INFO) << "resetLockout";
    scheduleStateOrCrash(SessionState::RESETTING_LOCKOUT);

    mWorker->schedule(Callable::from([this, cookie, hat] {
        enterStateOrCrash(cookie, SessionState::RESETTING_LOCKOUT);
        mEngine->resetLockoutImpl(mCb.get(), hat);
        enterIdling(cookie);
    }));

    return ndk::ScopedAStatus::ok();
}

ndk::ScopedAStatus Session::close(int32_t /*cookie*/) {
ndk::ScopedAStatus Session::close(int32_t cookie) {
    LOG(INFO) << "close";
    CHECK(mCurrentState == SessionState::IDLING) << "Can't close a non-idling session. Crashing.";
    mCurrentState = SessionState::CLOSED;
    mCb->onStateChanged(cookie, mCurrentState);
    return ndk::ScopedAStatus::ok();
}

@@ -119,4 +242,5 @@ ndk::ScopedAStatus Session::onUiReady() {
    LOG(INFO) << "onUiReady";
    return ndk::ScopedAStatus::ok();
}

}  // namespace aidl::android::hardware::biometrics::fingerprint
+3 −3
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ WorkerThread::~WorkerThread() {
    mThread.join();
}

bool WorkerThread::schedule(Task&& task) {
bool WorkerThread::schedule(std::unique_ptr<Callable> task) {
    if (mIsDestructing) {
        return false;
    }
@@ -58,10 +58,10 @@ void WorkerThread::threadFunc() {
        if (mIsDestructing) {
            return;
        }
        Task task = std::move(mQueue.front());
        std::unique_ptr<Callable> task = std::move(mQueue.front());
        mQueue.pop_front();
        lock.unlock();
        task();
        (*task)();
    }
}

Loading