Refactored biometric libraries into common
Test: atest
Bug: 230514750
Change-Id: I47ad020004ffef9646281611a637e1a5208f5573
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 70fadfe..31fd96b 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -15,11 +15,9 @@
vintf_fragments: ["fingerprint-example.xml"],
local_include_dirs: ["include"],
srcs: [
- "CancellationSignal.cpp",
"FakeFingerprintEngine.cpp",
"Fingerprint.cpp",
"Session.cpp",
- "WorkerThread.cpp",
"main.cpp",
],
shared_libs: [
@@ -27,28 +25,16 @@
"libbinder_ndk",
"android.hardware.biometrics.fingerprint-V2-ndk",
"android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.biometrics.common.thread",
+ "android.hardware.biometrics.common.util",
],
static_libs: ["android.hardware.biometrics.fingerprint.VirtualProps"],
}
-cc_test_host {
- name: "android.hardware.biometrics.fingerprint.WorkerThreadTest",
- local_include_dirs: ["include"],
- srcs: [
- "tests/WorkerThreadTest.cpp",
- "WorkerThread.cpp",
- ],
- shared_libs: [
- "libcutils",
- ],
- test_suites: ["general-tests"],
-}
-
cc_test {
name: "android.hardware.biometrics.fingerprint.FakeFingerprintEngineTest",
local_include_dirs: ["include"],
srcs: [
- "CancellationSignal.cpp",
"tests/FakeFingerprintEngineTest.cpp",
"FakeFingerprintEngine.cpp",
],
@@ -61,6 +47,7 @@
"android.hardware.biometrics.fingerprint-V2-ndk",
"android.hardware.biometrics.common-V2-ndk",
"android.hardware.keymaster-V3-ndk",
+ "android.hardware.biometrics.common.util",
],
vendor: true,
test_suites: ["general-tests"],
diff --git a/biometrics/fingerprint/aidl/default/CancellationSignal.cpp b/biometrics/fingerprint/aidl/default/CancellationSignal.cpp
deleted file mode 100644
index 6598316..0000000
--- a/biometrics/fingerprint/aidl/default/CancellationSignal.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index d1fe183..d0250af 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -16,14 +16,15 @@
#include "FakeFingerprintEngine.h"
-#include <fingerprint.sysprop.h>
-#include "CancellationSignal.h"
-
#include <android-base/logging.h>
+
+#include <fingerprint.sysprop.h>
#include <chrono>
#include <regex>
#include <thread>
+#include "util/CancellationSignal.h"
+
#define SLEEP_MS(x) \
if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
#define BEGIN_OP(x) \
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index 078d3d9..ab91e98 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -18,7 +18,7 @@
#include <android-base/logging.h>
-#include "CancellationSignal.h"
+#include "util/CancellationSignal.h"
namespace aidl::android::hardware::biometrics::fingerprint {
diff --git a/biometrics/fingerprint/aidl/default/WorkerThread.cpp b/biometrics/fingerprint/aidl/default/WorkerThread.cpp
deleted file mode 100644
index 34ebb5c..0000000
--- a/biometrics/fingerprint/aidl/default/WorkerThread.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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 "WorkerThread.h"
-
-namespace aidl::android::hardware::biometrics::fingerprint {
-
-// It's important that mThread is initialized after everything else because it runs a member
-// function that may use any member of this class.
-WorkerThread::WorkerThread(size_t maxQueueSize)
- : mMaxSize(maxQueueSize),
- mIsDestructing(false),
- mQueue(),
- mQueueMutex(),
- mQueueCond(),
- mThread(&WorkerThread::threadFunc, this) {}
-
-WorkerThread::~WorkerThread() {
- // This is a signal for threadFunc to terminate as soon as possible, and a hint for schedule
- // that it doesn't need to do any work.
- {
- std::unique_lock<std::mutex> lock(mQueueMutex);
- mIsDestructing = true;
- }
- mQueueCond.notify_all();
- mThread.join();
-}
-
-bool WorkerThread::schedule(std::unique_ptr<Callable> task) {
- if (mIsDestructing) {
- return false;
- }
-
- std::unique_lock<std::mutex> lock(mQueueMutex);
- if (mQueue.size() >= mMaxSize) {
- return false;
- }
- mQueue.push_back(std::move(task));
- lock.unlock();
- mQueueCond.notify_one();
- return true;
-}
-
-void WorkerThread::threadFunc() {
- while (!mIsDestructing) {
- std::unique_lock<std::mutex> lock(mQueueMutex);
- mQueueCond.wait(lock, [this] { return !mQueue.empty() || mIsDestructing; });
- if (mIsDestructing) {
- return;
- }
- std::unique_ptr<Callable> task = std::move(mQueue.front());
- mQueue.pop_front();
- lock.unlock();
- (*task)();
- }
-}
-
-} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/Callable.h b/biometrics/fingerprint/aidl/default/include/Callable.h
deleted file mode 100644
index c629511..0000000
--- a/biometrics/fingerprint/aidl/default/include/Callable.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-namespace aidl::android::hardware::biometrics::fingerprint {
-
-// Interface for representing parameterless functions. Unlike std::function<void()>, this can also
-// represent move-only lambdas.
-class Callable {
- public:
- virtual void operator()() = 0;
- virtual ~Callable() = default;
-
- // Creates a heap-allocated Callable instance from any function object.
- template <typename T>
- static std::unique_ptr<Callable> from(T func);
-
- private:
- template <typename T>
- class AnyFuncWrapper;
-};
-
-// Private helper class for wrapping any function object into a Callable.
-template <typename T>
-class Callable::AnyFuncWrapper : public Callable {
- public:
- explicit AnyFuncWrapper(T func) : mFunc(std::move(func)) {}
-
- void operator()() override { mFunc(); }
-
- private:
- T mFunc;
-};
-
-template <typename T>
-std::unique_ptr<Callable> Callable::from(T func) {
- return std::make_unique<AnyFuncWrapper<T>>(std::move(func));
-}
-
-} // namespace aidl::android::hardware::biometrics::fingerprint
\ No newline at end of file
diff --git a/biometrics/fingerprint/aidl/default/include/CancellationSignal.h b/biometrics/fingerprint/aidl/default/include/CancellationSignal.h
deleted file mode 100644
index 99f2fba..0000000
--- a/biometrics/fingerprint/aidl/default/include/CancellationSignal.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
-#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
-#include <functional>
-#include <future>
-
-#include "WorkerThread.h"
-
-namespace aidl::android::hardware::biometrics::fingerprint {
-
-class CancellationSignal : public common::BnCancellationSignal {
- public:
- explicit CancellationSignal(std::promise<void>&& cancellationPromise);
-
- ndk::ScopedAStatus cancel() override;
-
- private:
- std::promise<void> mCancellationPromise;
-};
-
-// Returns whether the given cancellation future is ready, i.e. whether the operation corresponding
-// to this future should be cancelled.
-bool shouldCancel(const std::future<void>& cancellationFuture);
-
-} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 8659b79..eb810da 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -15,12 +15,13 @@
*/
#pragma once
-
+#include <aidl/android/hardware/biometrics/common/SensorStrength.h>
#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
#include <random>
-#include "CancellationSignal.h"
+#include <future>
+#include <vector>
using namespace ::aidl::android::hardware::biometrics::common;
diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
index 7bd3d6d..20def0c 100644
--- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -20,7 +20,7 @@
#include "FakeFingerprintEngine.h"
#include "Session.h"
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
namespace aidl::android::hardware::biometrics::fingerprint {
diff --git a/biometrics/fingerprint/aidl/default/include/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h
index acd5def..104d819 100644
--- a/biometrics/fingerprint/aidl/default/include/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -20,7 +20,7 @@
#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
#include "FakeFingerprintEngine.h"
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
namespace aidl::android::hardware::biometrics::fingerprint {
diff --git a/biometrics/fingerprint/aidl/default/include/WorkerThread.h b/biometrics/fingerprint/aidl/default/include/WorkerThread.h
deleted file mode 100644
index 6fff4f2..0000000
--- a/biometrics/fingerprint/aidl/default/include/WorkerThread.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <mutex>
-#include <optional>
-#include <queue>
-#include <thread>
-
-#include "Callable.h"
-
-namespace aidl::android::hardware::biometrics::fingerprint {
-
-// A class that encapsulates a worker thread and a task queue, and provides a convenient interface
-// for a Session to schedule its tasks for asynchronous execution.
-class WorkerThread final {
- public:
- // Internally creates a queue that cannot exceed maxQueueSize elements and a new thread that
- // polls the queue for tasks until this instance is destructed.
- explicit WorkerThread(size_t maxQueueSize);
-
- // Unblocks the internal queue and calls join on the internal thread allowing it to gracefully
- // exit.
- ~WorkerThread();
-
- // Disallow copying this class.
- WorkerThread(const WorkerThread&) = delete;
- WorkerThread& operator=(const WorkerThread&) = delete;
-
- // Also disable moving this class to simplify implementation.
- WorkerThread(WorkerThread&&) = delete;
- WorkerThread& operator=(WorkerThread&&) = delete;
-
- // If the internal queue is not full, pushes a task at the end of the queue and returns true.
- // Otherwise, returns false. If the queue is busy, blocks until it becomes available.
- // This method expects heap-allocated tasks because it's the simplest way to represent function
- // objects of any type. Stack-allocated std::function could be used instead, but it cannot
- // represent functions with move-only captures because std::function is inherently copyable.
- // Not being able to pass move-only lambdas is a major limitation for the HAL implementation,
- // so heap-allocated tasks that share a common interface (Callable) were chosen instead.
- bool schedule(std::unique_ptr<Callable> task);
-
- private:
- // The function that runs on the internal thread. Sequentially runs the available tasks from
- // the queue. If the queue is empty, waits until a new task is added. If the worker is being
- // destructed, finishes its current task and gracefully exits.
- void threadFunc();
-
- // The maximum size that the queue is allowed to expand to.
- size_t mMaxSize;
-
- // Whether the destructor was called. If true, tells threadFunc to exit as soon as possible, and
- // tells schedule to avoid doing any work.
- std::atomic<bool> mIsDestructing;
-
- // Queue that's guarded by mQueueMutex and mQueueCond.
- std::deque<std::unique_ptr<Callable>> mQueue;
- std::mutex mQueueMutex;
- std::condition_variable mQueueCond;
-
- // The internal thread that works on the tasks from the queue.
- std::thread mThread;
-};
-
-} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp b/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
deleted file mode 100644
index 902fb40..0000000
--- a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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 <algorithm>
-#include <chrono>
-#include <future>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-#include "WorkerThread.h"
-
-namespace {
-
-using aidl::android::hardware::biometrics::fingerprint::Callable;
-using aidl::android::hardware::biometrics::fingerprint::WorkerThread;
-using namespace std::chrono_literals;
-
-TEST(WorkerThreadTest, ScheduleReturnsTrueWhenQueueHasSpace) {
- WorkerThread worker(1 /*maxQueueSize*/);
- for (int i = 0; i < 100; ++i) {
- std::promise<void> promise;
- auto future = promise.get_future();
-
- ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise)]() mutable {
- // Notify that the task has started.
- promise.set_value();
- })));
-
- future.wait();
- }
-}
-
-TEST(WorkerThreadTest, ScheduleReturnsFalseWhenQueueIsFull) {
- WorkerThread worker(2 /*maxQueueSize*/);
-
- std::promise<void> promise;
- auto future = promise.get_future();
-
- // Schedule a long-running task.
- ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise)]() mutable {
- // Notify that the task has started.
- promise.set_value();
- // Block for a "very long" time.
- std::this_thread::sleep_for(1s);
- })));
-
- // Make sure the long-running task began executing.
- future.wait();
-
- // The first task is already being worked on, which means the queue must be empty.
- // Fill the worker's queue to the maximum.
- ASSERT_TRUE(worker.schedule(Callable::from([] {})));
- ASSERT_TRUE(worker.schedule(Callable::from([] {})));
-
- EXPECT_FALSE(worker.schedule(Callable::from([] {})));
-}
-
-TEST(WorkerThreadTest, TasksExecuteInOrder) {
- constexpr int NUM_TASKS = 10000;
- WorkerThread worker(NUM_TASKS + 1);
-
- std::mutex mut;
- std::condition_variable cv;
- bool finished = false;
- std::vector<int> results;
-
- for (int i = 0; i < NUM_TASKS; ++i) {
- worker.schedule(Callable::from([&mut, &results, i] {
- // Delay tasks differently to provoke races.
- std::this_thread::sleep_for(std::chrono::nanoseconds(100 - i % 100));
- auto lock = std::lock_guard(mut);
- results.push_back(i);
- }));
- }
-
- // Schedule a special task to signal when all of the tasks are finished.
- worker.schedule(Callable::from([&mut, &cv, &finished] {
- auto lock = std::lock_guard(mut);
- finished = true;
- cv.notify_one();
- }));
-
- auto lock = std::unique_lock(mut);
- cv.wait(lock, [&finished] { return finished; });
- ASSERT_EQ(results.size(), NUM_TASKS);
- EXPECT_TRUE(std::is_sorted(results.begin(), results.end()));
-}
-
-TEST(WorkerThreadTest, ExecutionStopsAfterWorkerIsDestroyed) {
- std::promise<void> promise1;
- std::promise<void> promise2;
- auto future1 = promise1.get_future();
- auto future2 = promise2.get_future();
- std::atomic<bool> value;
-
- // Local scope for the worker to test its destructor when it goes out of scope.
- {
- WorkerThread worker(2 /*maxQueueSize*/);
-
- ASSERT_TRUE(worker.schedule(Callable::from([promise = std::move(promise1)]() mutable {
- promise.set_value();
- std::this_thread::sleep_for(200ms);
- })));
-
- // The first task should start executing.
- future1.wait();
-
- // The second task should schedule successfully.
- ASSERT_TRUE(
- worker.schedule(Callable::from([promise = std::move(promise2), &value]() mutable {
- // The worker should destruct before it gets a chance to execute this.
- value = true;
- promise.set_value();
- })));
- }
-
- // The second task should never execute.
- future2.wait();
- // The future is expected to be ready but contain an exception.
- // Cannot use ASSERT_THROW because exceptions are disabled in this codebase.
- // ASSERT_THROW(future2.get(), std::future_error);
- EXPECT_FALSE(value);
-}
-
-} // namespace