Implement the state machine
Bug: 166800618
Bug: 175070939
Test: atest VtsHalBiometricsFingerprintTargetTest
Change-Id: I3a908b0f910323d643b220e560e9c2d8e4c5675a
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index c928df4..f6a0314 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -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);
+}
-Session::Session(std::shared_ptr<ISessionCallback> cb) : mCb(std::move(cb)) {}
+void Session::scheduleStateOrCrash(SessionState state) {
+ CHECK(mScheduledState == SessionState::IDLING);
+ CHECK(mCurrentState == SessionState::IDLING);
+ mScheduledState = state;
+}
-ndk::ScopedAStatus Session::generateChallenge(int32_t /*cookie*/, int32_t /*timeoutSec*/) {
+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) {
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);
- }
- *out = SharedRefBase::make<CancellationSignal>();
+ 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);
+ }
+ 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 @@
LOG(INFO) << "onUiReady";
return ndk::ScopedAStatus::ok();
}
+
} // namespace aidl::android::hardware::biometrics::fingerprint