Use InputProcessor instead of InputClassifier
Convert InputClassifier to aidl and use it inside framework's
InputClassifier.
Bug: 167946763
Test: verified on the actual device
Change-Id: I62520d424a42bead59904d5a9accea5325b9e8cb
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 6c4b11e..3ea0986 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -17,13 +17,15 @@
#define LOG_TAG "InputClassifier"
#include "InputClassifier.h"
-#include "InputClassifierConverter.h"
+#include "InputCommonConverter.h"
-#include <algorithm>
#include <android-base/stringprintf.h>
-#include <cmath>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <inttypes.h>
#include <log/log.h>
+#include <algorithm>
+#include <cmath>
#if defined(__linux__)
#include <pthread.h>
#endif
@@ -36,10 +38,9 @@
#define INDENT5 " "
using android::base::StringPrintf;
-using android::hardware::hidl_bitfield;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using namespace android::hardware::input;
+using namespace std::chrono_literals;
+using namespace ::aidl::android::hardware::input;
+using aidl::android::hardware::input::processor::IInputProcessor;
namespace android {
@@ -55,13 +56,13 @@
return it->second;
}
-static MotionClassification getMotionClassification(common::V1_0::Classification classification) {
+static MotionClassification getMotionClassification(common::Classification classification) {
static_assert(MotionClassification::NONE ==
- static_cast<MotionClassification>(common::V1_0::Classification::NONE));
+ static_cast<MotionClassification>(common::Classification::NONE));
static_assert(MotionClassification::AMBIGUOUS_GESTURE ==
- static_cast<MotionClassification>(common::V1_0::Classification::AMBIGUOUS_GESTURE));
+ static_cast<MotionClassification>(common::Classification::AMBIGUOUS_GESTURE));
static_assert(MotionClassification::DEEP_PRESS ==
- static_cast<MotionClassification>(common::V1_0::Classification::DEEP_PRESS));
+ static_cast<MotionClassification>(common::Classification::DEEP_PRESS));
return static_cast<MotionClassification>(classification);
}
@@ -70,6 +71,56 @@
isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN);
}
+static void setCurrentThreadName(const char* name) {
+#if defined(__linux__)
+ // Set the thread name for debugging
+ pthread_setname_np(pthread_self(), name);
+#else
+ (void*)(name); // prevent unused variable warning
+#endif
+}
+
+static std::shared_ptr<IInputProcessor> getService() {
+ const std::string aidl_instance_name = std::string(IInputProcessor::descriptor) + "/default";
+
+ if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
+ ALOGI("HAL %s is not declared", aidl_instance_name.c_str());
+ return nullptr;
+ }
+
+ ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_instance_name.c_str()));
+ return IInputProcessor::fromBinder(binder);
+}
+
+// Temporarily releases a held mutex for the lifetime of the instance.
+// Named to match std::scoped_lock
+class scoped_unlock {
+public:
+ explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); }
+ ~scoped_unlock() { mMutex.lock(); }
+
+private:
+ std::mutex& mMutex;
+};
+
+// --- ScopedDeathRecipient ---
+ScopedDeathRecipient::ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied,
+ void* cookie)
+ : mCookie(cookie) {
+ mRecipient = AIBinder_DeathRecipient_new(onBinderDied);
+}
+
+void ScopedDeathRecipient::linkToDeath(AIBinder* binder) {
+ binder_status_t linked = AIBinder_linkToDeath(binder, mRecipient, mCookie);
+ if (linked != STATUS_OK) {
+ ALOGE("Could not link death recipient to the HAL death");
+ }
+}
+
+ScopedDeathRecipient::~ScopedDeathRecipient() {
+ AIBinder_DeathRecipient_delete(mRecipient);
+}
+
// --- ClassifierEvent ---
ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
@@ -118,9 +169,8 @@
// --- MotionClassifier ---
-MotionClassifier::MotionClassifier(
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service)
- : mEvents(MAX_EVENTS), mService(service) {
+MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> service)
+ : mEvents(MAX_EVENTS), mService(std::move(service)) {
// Under normal operation, we do not need to reset the HAL here. But in the case where system
// crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
// have received events in the past. That means, that HAL could be in an inconsistent state
@@ -135,23 +185,10 @@
}
std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
- sp<android::hardware::hidl_death_recipient> deathRecipient) {
- sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
- classifier::V1_0::IInputClassifier::getService();
- if (!service) {
- // Not really an error, maybe the device does not have this HAL,
- // but somehow the feature flag is flipped
- ALOGI("Could not obtain InputClassifier HAL");
- return nullptr;
- }
-
- const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false);
- if (!linked) {
- ALOGE("Could not link death recipient to the HAL death");
- return nullptr;
- }
+ std::shared_ptr<IInputProcessor> service) {
+ LOG_ALWAYS_FATAL_IF(service == nullptr);
// Using 'new' to access a non-public constructor
- return std::unique_ptr<MotionClassifier>(new MotionClassifier(service));
+ return std::unique_ptr<MotionClassifier>(new MotionClassifier(std::move(service)));
}
MotionClassifier::~MotionClassifier() {
@@ -176,14 +213,12 @@
switch (event.type) {
case ClassifierEventType::MOTION: {
NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get());
- common::V1_0::MotionEvent motionEvent =
- notifyMotionArgsToHalMotionEvent(*motionArgs);
- Return<common::V1_0::Classification> response = mService->classify(motionEvent);
- halResponseOk = response.isOk();
- if (halResponseOk) {
- common::V1_0::Classification halClassification = response;
+ common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs);
+ common::Classification classification;
+ ndk::ScopedAStatus response = mService->classify(motionEvent, &classification);
+ if (response.isOk()) {
updateClassification(motionArgs->deviceId, motionArgs->eventTime,
- getMotionClassification(halClassification));
+ getMotionClassification(classification));
}
break;
}
@@ -300,7 +335,8 @@
if (!mService) {
return "null";
}
- if (mService->ping().isOk()) {
+
+ if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) {
return "running";
}
return "not responding";
@@ -329,40 +365,53 @@
}
}
-// --- HalDeathRecipient
-
-InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {}
-
-void InputClassifier::HalDeathRecipient::serviceDied(
- uint64_t cookie, const wp<android::hidl::base::V1_0::IBase>& who) {
- sp<android::hidl::base::V1_0::IBase> service = who.promote();
- if (service) {
- service->unlinkToDeath(this);
- }
- mParent.setMotionClassifier(nullptr);
-}
-
// --- InputClassifier ---
-InputClassifier::InputClassifier(InputListenerInterface& listener)
- : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
+InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {}
+
+void InputClassifier::onBinderDied(void* cookie) {
+ InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
+ if (classifier == nullptr) {
+ LOG_ALWAYS_FATAL("Cookie is not valid");
+ return;
+ }
+ classifier->setMotionClassifierEnabled(false);
+}
void InputClassifier::setMotionClassifierEnabled(bool enabled) {
+ std::scoped_lock lock(mLock);
if (enabled) {
ALOGI("Enabling motion classifier");
- if (mInitializeMotionClassifierThread.joinable()) {
- mInitializeMotionClassifierThread.join();
+ if (mInitializeMotionClassifier.valid()) {
+ scoped_unlock unlock(mLock);
+ std::future_status status = mInitializeMotionClassifier.wait_for(5s);
+ if (status != std::future_status::ready) {
+ /**
+ * We don't have a better option here than to crash. We can't stop the thread,
+ * and we can't continue because 'mInitializeMotionClassifier' will block in its
+ * destructor.
+ */
+ LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!");
+ }
}
- mInitializeMotionClassifierThread = std::thread(
- [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); });
-#if defined(__linux__)
- // Set the thread name for debugging
- pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
- "Create MotionClassifier");
-#endif
+ mInitializeMotionClassifier = std::async(std::launch::async, [this] {
+ setCurrentThreadName("Create MotionClassifier");
+ std::shared_ptr<IInputProcessor> service = getService();
+ if (service == nullptr) {
+ // Keep the MotionClassifier null, no service was found
+ return;
+ }
+ { // acquire lock
+ std::scoped_lock threadLock(mLock);
+ mHalDeathRecipient =
+ std::make_unique<ScopedDeathRecipient>(onBinderDied, this /*cookie*/);
+ mHalDeathRecipient->linkToDeath(service->asBinder().get());
+ setMotionClassifierLocked(MotionClassifier::create(std::move(service)));
+ } // release lock
+ });
} else {
ALOGI("Disabling motion classifier");
- setMotionClassifier(nullptr);
+ setMotionClassifierLocked(nullptr);
}
}
@@ -419,9 +468,13 @@
mListener.notifyPointerCaptureChanged(args);
}
-void InputClassifier::setMotionClassifier(
- std::unique_ptr<MotionClassifierInterface> motionClassifier) {
- std::scoped_lock lock(mLock);
+void InputClassifier::setMotionClassifierLocked(
+ std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
+ if (motionClassifier == nullptr) {
+ // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath.
+ // We can't call 'unlink' here because we don't have the binder handle.
+ mHalDeathRecipient = nullptr;
+ }
mMotionClassifier = std::move(motionClassifier);
}
@@ -438,9 +491,6 @@
}
InputClassifier::~InputClassifier() {
- if (mInitializeMotionClassifierThread.joinable()) {
- mInitializeMotionClassifierThread.join();
- }
}
} // namespace android