1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "InputProcessor"
18*38e8c45fSAndroid Build Coastguard Worker
19*38e8c45fSAndroid Build Coastguard Worker #include "InputProcessor.h"
20*38e8c45fSAndroid Build Coastguard Worker #include "InputCommonConverter.h"
21*38e8c45fSAndroid Build Coastguard Worker
22*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <android/binder_manager.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <android/binder_process.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <input/Input.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <algorithm>
29*38e8c45fSAndroid Build Coastguard Worker #include <cmath>
30*38e8c45fSAndroid Build Coastguard Worker #if defined(__linux__)
31*38e8c45fSAndroid Build Coastguard Worker #include <pthread.h>
32*38e8c45fSAndroid Build Coastguard Worker #endif
33*38e8c45fSAndroid Build Coastguard Worker #include <unordered_set>
34*38e8c45fSAndroid Build Coastguard Worker
35*38e8c45fSAndroid Build Coastguard Worker #define INDENT1 " "
36*38e8c45fSAndroid Build Coastguard Worker #define INDENT2 " "
37*38e8c45fSAndroid Build Coastguard Worker #define INDENT3 " "
38*38e8c45fSAndroid Build Coastguard Worker #define INDENT4 " "
39*38e8c45fSAndroid Build Coastguard Worker #define INDENT5 " "
40*38e8c45fSAndroid Build Coastguard Worker
41*38e8c45fSAndroid Build Coastguard Worker using android::base::StringPrintf;
42*38e8c45fSAndroid Build Coastguard Worker using namespace std::chrono_literals;
43*38e8c45fSAndroid Build Coastguard Worker using namespace ::aidl::android::hardware::input;
44*38e8c45fSAndroid Build Coastguard Worker using aidl::android::hardware::input::processor::IInputProcessor;
45*38e8c45fSAndroid Build Coastguard Worker
46*38e8c45fSAndroid Build Coastguard Worker namespace android {
47*38e8c45fSAndroid Build Coastguard Worker
48*38e8c45fSAndroid Build Coastguard Worker // Max number of elements to store in mEvents.
49*38e8c45fSAndroid Build Coastguard Worker static constexpr size_t MAX_EVENTS = 5;
50*38e8c45fSAndroid Build Coastguard Worker
51*38e8c45fSAndroid Build Coastguard Worker template <class K, class V>
getValueForKey(const std::unordered_map<K,V> & map,K key,V defaultValue)52*38e8c45fSAndroid Build Coastguard Worker static V getValueForKey(const std::unordered_map<K, V>& map, K key, V defaultValue) {
53*38e8c45fSAndroid Build Coastguard Worker auto it = map.find(key);
54*38e8c45fSAndroid Build Coastguard Worker if (it == map.end()) {
55*38e8c45fSAndroid Build Coastguard Worker return defaultValue;
56*38e8c45fSAndroid Build Coastguard Worker }
57*38e8c45fSAndroid Build Coastguard Worker return it->second;
58*38e8c45fSAndroid Build Coastguard Worker }
59*38e8c45fSAndroid Build Coastguard Worker
getMotionClassification(common::Classification classification)60*38e8c45fSAndroid Build Coastguard Worker static MotionClassification getMotionClassification(common::Classification classification) {
61*38e8c45fSAndroid Build Coastguard Worker static_assert(MotionClassification::NONE ==
62*38e8c45fSAndroid Build Coastguard Worker static_cast<MotionClassification>(common::Classification::NONE));
63*38e8c45fSAndroid Build Coastguard Worker static_assert(MotionClassification::AMBIGUOUS_GESTURE ==
64*38e8c45fSAndroid Build Coastguard Worker static_cast<MotionClassification>(common::Classification::AMBIGUOUS_GESTURE));
65*38e8c45fSAndroid Build Coastguard Worker static_assert(MotionClassification::DEEP_PRESS ==
66*38e8c45fSAndroid Build Coastguard Worker static_cast<MotionClassification>(common::Classification::DEEP_PRESS));
67*38e8c45fSAndroid Build Coastguard Worker return static_cast<MotionClassification>(classification);
68*38e8c45fSAndroid Build Coastguard Worker }
69*38e8c45fSAndroid Build Coastguard Worker
isTouchEvent(const NotifyMotionArgs & args)70*38e8c45fSAndroid Build Coastguard Worker static bool isTouchEvent(const NotifyMotionArgs& args) {
71*38e8c45fSAndroid Build Coastguard Worker return isFromSource(args.source, AINPUT_SOURCE_TOUCHPAD) ||
72*38e8c45fSAndroid Build Coastguard Worker isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN);
73*38e8c45fSAndroid Build Coastguard Worker }
74*38e8c45fSAndroid Build Coastguard Worker
setCurrentThreadName(const char * name)75*38e8c45fSAndroid Build Coastguard Worker static void setCurrentThreadName(const char* name) {
76*38e8c45fSAndroid Build Coastguard Worker #if defined(__linux__)
77*38e8c45fSAndroid Build Coastguard Worker // Set the thread name for debugging
78*38e8c45fSAndroid Build Coastguard Worker pthread_setname_np(pthread_self(), name);
79*38e8c45fSAndroid Build Coastguard Worker #else
80*38e8c45fSAndroid Build Coastguard Worker (void*)(name); // prevent unused variable warning
81*38e8c45fSAndroid Build Coastguard Worker #endif
82*38e8c45fSAndroid Build Coastguard Worker }
83*38e8c45fSAndroid Build Coastguard Worker
getService()84*38e8c45fSAndroid Build Coastguard Worker static std::shared_ptr<IInputProcessor> getService() {
85*38e8c45fSAndroid Build Coastguard Worker const std::string aidl_instance_name = std::string(IInputProcessor::descriptor) + "/default";
86*38e8c45fSAndroid Build Coastguard Worker
87*38e8c45fSAndroid Build Coastguard Worker if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) {
88*38e8c45fSAndroid Build Coastguard Worker ALOGI("HAL %s is not declared", aidl_instance_name.c_str());
89*38e8c45fSAndroid Build Coastguard Worker return nullptr;
90*38e8c45fSAndroid Build Coastguard Worker }
91*38e8c45fSAndroid Build Coastguard Worker
92*38e8c45fSAndroid Build Coastguard Worker ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_instance_name.c_str()));
93*38e8c45fSAndroid Build Coastguard Worker return IInputProcessor::fromBinder(binder);
94*38e8c45fSAndroid Build Coastguard Worker }
95*38e8c45fSAndroid Build Coastguard Worker
96*38e8c45fSAndroid Build Coastguard Worker // Temporarily releases a held mutex for the lifetime of the instance.
97*38e8c45fSAndroid Build Coastguard Worker // Named to match std::scoped_lock
98*38e8c45fSAndroid Build Coastguard Worker class scoped_unlock {
99*38e8c45fSAndroid Build Coastguard Worker public:
scoped_unlock(std::mutex & mutex)100*38e8c45fSAndroid Build Coastguard Worker explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); }
~scoped_unlock()101*38e8c45fSAndroid Build Coastguard Worker ~scoped_unlock() { mMutex.lock(); }
102*38e8c45fSAndroid Build Coastguard Worker
103*38e8c45fSAndroid Build Coastguard Worker private:
104*38e8c45fSAndroid Build Coastguard Worker std::mutex& mMutex;
105*38e8c45fSAndroid Build Coastguard Worker };
106*38e8c45fSAndroid Build Coastguard Worker
107*38e8c45fSAndroid Build Coastguard Worker // --- ScopedDeathRecipient ---
ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied,void * cookie)108*38e8c45fSAndroid Build Coastguard Worker ScopedDeathRecipient::ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied,
109*38e8c45fSAndroid Build Coastguard Worker void* cookie)
110*38e8c45fSAndroid Build Coastguard Worker : mCookie(cookie) {
111*38e8c45fSAndroid Build Coastguard Worker mRecipient = AIBinder_DeathRecipient_new(onBinderDied);
112*38e8c45fSAndroid Build Coastguard Worker }
113*38e8c45fSAndroid Build Coastguard Worker
linkToDeath(AIBinder * binder)114*38e8c45fSAndroid Build Coastguard Worker void ScopedDeathRecipient::linkToDeath(AIBinder* binder) {
115*38e8c45fSAndroid Build Coastguard Worker binder_status_t linked = AIBinder_linkToDeath(binder, mRecipient, mCookie);
116*38e8c45fSAndroid Build Coastguard Worker if (linked != STATUS_OK) {
117*38e8c45fSAndroid Build Coastguard Worker ALOGE("Could not link death recipient to the HAL death");
118*38e8c45fSAndroid Build Coastguard Worker }
119*38e8c45fSAndroid Build Coastguard Worker }
120*38e8c45fSAndroid Build Coastguard Worker
~ScopedDeathRecipient()121*38e8c45fSAndroid Build Coastguard Worker ScopedDeathRecipient::~ScopedDeathRecipient() {
122*38e8c45fSAndroid Build Coastguard Worker AIBinder_DeathRecipient_delete(mRecipient);
123*38e8c45fSAndroid Build Coastguard Worker }
124*38e8c45fSAndroid Build Coastguard Worker
125*38e8c45fSAndroid Build Coastguard Worker // --- ClassifierEvent ---
126*38e8c45fSAndroid Build Coastguard Worker
ClassifierEvent(const NotifyMotionArgs & args)127*38e8c45fSAndroid Build Coastguard Worker ClassifierEvent::ClassifierEvent(const NotifyMotionArgs& args)
128*38e8c45fSAndroid Build Coastguard Worker : type(ClassifierEventType::MOTION), args(args){};
129*38e8c45fSAndroid Build Coastguard Worker
ClassifierEvent(const NotifyDeviceResetArgs & args)130*38e8c45fSAndroid Build Coastguard Worker ClassifierEvent::ClassifierEvent(const NotifyDeviceResetArgs& args)
131*38e8c45fSAndroid Build Coastguard Worker : type(ClassifierEventType::DEVICE_RESET), args(args){};
132*38e8c45fSAndroid Build Coastguard Worker
ClassifierEvent(ClassifierEventType type,std::optional<NotifyArgs> args)133*38e8c45fSAndroid Build Coastguard Worker ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::optional<NotifyArgs> args)
134*38e8c45fSAndroid Build Coastguard Worker : type(type), args(args){};
135*38e8c45fSAndroid Build Coastguard Worker
operator =(ClassifierEvent && other)136*38e8c45fSAndroid Build Coastguard Worker ClassifierEvent& ClassifierEvent::operator=(ClassifierEvent&& other) {
137*38e8c45fSAndroid Build Coastguard Worker type = other.type;
138*38e8c45fSAndroid Build Coastguard Worker args = other.args;
139*38e8c45fSAndroid Build Coastguard Worker return *this;
140*38e8c45fSAndroid Build Coastguard Worker }
141*38e8c45fSAndroid Build Coastguard Worker
createHalResetEvent()142*38e8c45fSAndroid Build Coastguard Worker ClassifierEvent ClassifierEvent::createHalResetEvent() {
143*38e8c45fSAndroid Build Coastguard Worker return ClassifierEvent(ClassifierEventType::HAL_RESET, std::nullopt);
144*38e8c45fSAndroid Build Coastguard Worker }
145*38e8c45fSAndroid Build Coastguard Worker
createExitEvent()146*38e8c45fSAndroid Build Coastguard Worker ClassifierEvent ClassifierEvent::createExitEvent() {
147*38e8c45fSAndroid Build Coastguard Worker return ClassifierEvent(ClassifierEventType::EXIT, std::nullopt);
148*38e8c45fSAndroid Build Coastguard Worker }
149*38e8c45fSAndroid Build Coastguard Worker
getDeviceId() const150*38e8c45fSAndroid Build Coastguard Worker std::optional<int32_t> ClassifierEvent::getDeviceId() const {
151*38e8c45fSAndroid Build Coastguard Worker switch (type) {
152*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::MOTION: {
153*38e8c45fSAndroid Build Coastguard Worker const NotifyMotionArgs& motionArgs = std::get<NotifyMotionArgs>(*args);
154*38e8c45fSAndroid Build Coastguard Worker return motionArgs.deviceId;
155*38e8c45fSAndroid Build Coastguard Worker }
156*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::DEVICE_RESET: {
157*38e8c45fSAndroid Build Coastguard Worker const NotifyDeviceResetArgs& deviceResetArgs = std::get<NotifyDeviceResetArgs>(*args);
158*38e8c45fSAndroid Build Coastguard Worker return deviceResetArgs.deviceId;
159*38e8c45fSAndroid Build Coastguard Worker }
160*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::HAL_RESET: {
161*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
162*38e8c45fSAndroid Build Coastguard Worker }
163*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::EXIT: {
164*38e8c45fSAndroid Build Coastguard Worker return std::nullopt;
165*38e8c45fSAndroid Build Coastguard Worker }
166*38e8c45fSAndroid Build Coastguard Worker }
167*38e8c45fSAndroid Build Coastguard Worker }
168*38e8c45fSAndroid Build Coastguard Worker
169*38e8c45fSAndroid Build Coastguard Worker // --- MotionClassifier ---
170*38e8c45fSAndroid Build Coastguard Worker
MotionClassifier(std::shared_ptr<IInputProcessor> service)171*38e8c45fSAndroid Build Coastguard Worker MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> service)
172*38e8c45fSAndroid Build Coastguard Worker : mEvents(MAX_EVENTS), mService(std::move(service)) {
173*38e8c45fSAndroid Build Coastguard Worker // Under normal operation, we do not need to reset the HAL here. But in the case where system
174*38e8c45fSAndroid Build Coastguard Worker // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already
175*38e8c45fSAndroid Build Coastguard Worker // have received events in the past. That means, that HAL could be in an inconsistent state
176*38e8c45fSAndroid Build Coastguard Worker // once it receives events from the newly created MotionClassifier.
177*38e8c45fSAndroid Build Coastguard Worker mEvents.push(ClassifierEvent::createHalResetEvent());
178*38e8c45fSAndroid Build Coastguard Worker
179*38e8c45fSAndroid Build Coastguard Worker mHalThread = std::thread(&MotionClassifier::processEvents, this);
180*38e8c45fSAndroid Build Coastguard Worker #if defined(__linux__)
181*38e8c45fSAndroid Build Coastguard Worker // Set the thread name for debugging
182*38e8c45fSAndroid Build Coastguard Worker pthread_setname_np(mHalThread.native_handle(), "InputProcessor");
183*38e8c45fSAndroid Build Coastguard Worker #endif
184*38e8c45fSAndroid Build Coastguard Worker }
185*38e8c45fSAndroid Build Coastguard Worker
create(std::shared_ptr<IInputProcessor> service)186*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
187*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<IInputProcessor> service) {
188*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(service == nullptr);
189*38e8c45fSAndroid Build Coastguard Worker // Using 'new' to access a non-public constructor
190*38e8c45fSAndroid Build Coastguard Worker return std::unique_ptr<MotionClassifier>(new MotionClassifier(std::move(service)));
191*38e8c45fSAndroid Build Coastguard Worker }
192*38e8c45fSAndroid Build Coastguard Worker
~MotionClassifier()193*38e8c45fSAndroid Build Coastguard Worker MotionClassifier::~MotionClassifier() {
194*38e8c45fSAndroid Build Coastguard Worker requestExit();
195*38e8c45fSAndroid Build Coastguard Worker mHalThread.join();
196*38e8c45fSAndroid Build Coastguard Worker }
197*38e8c45fSAndroid Build Coastguard Worker
198*38e8c45fSAndroid Build Coastguard Worker /**
199*38e8c45fSAndroid Build Coastguard Worker * Obtain the classification from the HAL for a given MotionEvent.
200*38e8c45fSAndroid Build Coastguard Worker * Should only be called from the InputProcessor thread (mHalThread).
201*38e8c45fSAndroid Build Coastguard Worker * Should not be called from the thread that notifyMotion runs on.
202*38e8c45fSAndroid Build Coastguard Worker *
203*38e8c45fSAndroid Build Coastguard Worker * There is no way to provide a timeout for a HAL call. So if the HAL takes too long
204*38e8c45fSAndroid Build Coastguard Worker * to return a classification, this would directly impact the touch latency.
205*38e8c45fSAndroid Build Coastguard Worker * To remove any possibility of negatively affecting the touch latency, the HAL
206*38e8c45fSAndroid Build Coastguard Worker * is called from a dedicated thread.
207*38e8c45fSAndroid Build Coastguard Worker */
processEvents()208*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::processEvents() {
209*38e8c45fSAndroid Build Coastguard Worker while (true) {
210*38e8c45fSAndroid Build Coastguard Worker ClassifierEvent event = mEvents.pop();
211*38e8c45fSAndroid Build Coastguard Worker bool halResponseOk = true;
212*38e8c45fSAndroid Build Coastguard Worker switch (event.type) {
213*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::MOTION: {
214*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs& motionArgs = std::get<NotifyMotionArgs>(*event.args);
215*38e8c45fSAndroid Build Coastguard Worker common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs);
216*38e8c45fSAndroid Build Coastguard Worker common::Classification classification;
217*38e8c45fSAndroid Build Coastguard Worker ndk::ScopedAStatus response = mService->classify(motionEvent, &classification);
218*38e8c45fSAndroid Build Coastguard Worker if (response.isOk()) {
219*38e8c45fSAndroid Build Coastguard Worker updateClassification(motionArgs.deviceId, motionArgs.eventTime,
220*38e8c45fSAndroid Build Coastguard Worker getMotionClassification(classification));
221*38e8c45fSAndroid Build Coastguard Worker }
222*38e8c45fSAndroid Build Coastguard Worker break;
223*38e8c45fSAndroid Build Coastguard Worker }
224*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::DEVICE_RESET: {
225*38e8c45fSAndroid Build Coastguard Worker const int32_t deviceId = *(event.getDeviceId());
226*38e8c45fSAndroid Build Coastguard Worker halResponseOk = mService->resetDevice(deviceId).isOk();
227*38e8c45fSAndroid Build Coastguard Worker clearDeviceState(deviceId);
228*38e8c45fSAndroid Build Coastguard Worker break;
229*38e8c45fSAndroid Build Coastguard Worker }
230*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::HAL_RESET: {
231*38e8c45fSAndroid Build Coastguard Worker halResponseOk = mService->reset().isOk();
232*38e8c45fSAndroid Build Coastguard Worker clearClassifications();
233*38e8c45fSAndroid Build Coastguard Worker break;
234*38e8c45fSAndroid Build Coastguard Worker }
235*38e8c45fSAndroid Build Coastguard Worker case ClassifierEventType::EXIT: {
236*38e8c45fSAndroid Build Coastguard Worker clearClassifications();
237*38e8c45fSAndroid Build Coastguard Worker return;
238*38e8c45fSAndroid Build Coastguard Worker }
239*38e8c45fSAndroid Build Coastguard Worker }
240*38e8c45fSAndroid Build Coastguard Worker if (!halResponseOk) {
241*38e8c45fSAndroid Build Coastguard Worker ALOGE("Error communicating with InputProcessor HAL. "
242*38e8c45fSAndroid Build Coastguard Worker "Exiting MotionClassifier HAL thread");
243*38e8c45fSAndroid Build Coastguard Worker clearClassifications();
244*38e8c45fSAndroid Build Coastguard Worker return;
245*38e8c45fSAndroid Build Coastguard Worker }
246*38e8c45fSAndroid Build Coastguard Worker }
247*38e8c45fSAndroid Build Coastguard Worker }
248*38e8c45fSAndroid Build Coastguard Worker
enqueueEvent(ClassifierEvent && event)249*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::enqueueEvent(ClassifierEvent&& event) {
250*38e8c45fSAndroid Build Coastguard Worker bool eventAdded = mEvents.push(std::move(event));
251*38e8c45fSAndroid Build Coastguard Worker if (!eventAdded) {
252*38e8c45fSAndroid Build Coastguard Worker // If the queue is full, suspect the HAL is slow in processing the events.
253*38e8c45fSAndroid Build Coastguard Worker ALOGE("Could not add the event to the queue. Resetting");
254*38e8c45fSAndroid Build Coastguard Worker reset();
255*38e8c45fSAndroid Build Coastguard Worker }
256*38e8c45fSAndroid Build Coastguard Worker }
257*38e8c45fSAndroid Build Coastguard Worker
requestExit()258*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::requestExit() {
259*38e8c45fSAndroid Build Coastguard Worker reset();
260*38e8c45fSAndroid Build Coastguard Worker mEvents.push(ClassifierEvent::createExitEvent());
261*38e8c45fSAndroid Build Coastguard Worker }
262*38e8c45fSAndroid Build Coastguard Worker
updateClassification(int32_t deviceId,nsecs_t eventTime,MotionClassification classification)263*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::updateClassification(int32_t deviceId, nsecs_t eventTime,
264*38e8c45fSAndroid Build Coastguard Worker MotionClassification classification) {
265*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
266*38e8c45fSAndroid Build Coastguard Worker const nsecs_t lastDownTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
267*38e8c45fSAndroid Build Coastguard Worker if (eventTime < lastDownTime) {
268*38e8c45fSAndroid Build Coastguard Worker // HAL just finished processing an event that belonged to an earlier gesture,
269*38e8c45fSAndroid Build Coastguard Worker // but new gesture is already in progress. Drop this classification.
270*38e8c45fSAndroid Build Coastguard Worker ALOGW("Received late classification. Late by at least %" PRId64 " ms.",
271*38e8c45fSAndroid Build Coastguard Worker nanoseconds_to_milliseconds(lastDownTime - eventTime));
272*38e8c45fSAndroid Build Coastguard Worker return;
273*38e8c45fSAndroid Build Coastguard Worker }
274*38e8c45fSAndroid Build Coastguard Worker mClassifications[deviceId] = classification;
275*38e8c45fSAndroid Build Coastguard Worker }
276*38e8c45fSAndroid Build Coastguard Worker
setClassification(int32_t deviceId,MotionClassification classification)277*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::setClassification(int32_t deviceId, MotionClassification classification) {
278*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
279*38e8c45fSAndroid Build Coastguard Worker mClassifications[deviceId] = classification;
280*38e8c45fSAndroid Build Coastguard Worker }
281*38e8c45fSAndroid Build Coastguard Worker
clearClassifications()282*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::clearClassifications() {
283*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
284*38e8c45fSAndroid Build Coastguard Worker mClassifications.clear();
285*38e8c45fSAndroid Build Coastguard Worker }
286*38e8c45fSAndroid Build Coastguard Worker
getClassification(int32_t deviceId)287*38e8c45fSAndroid Build Coastguard Worker MotionClassification MotionClassifier::getClassification(int32_t deviceId) {
288*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
289*38e8c45fSAndroid Build Coastguard Worker return getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
290*38e8c45fSAndroid Build Coastguard Worker }
291*38e8c45fSAndroid Build Coastguard Worker
updateLastDownTime(int32_t deviceId,nsecs_t downTime)292*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::updateLastDownTime(int32_t deviceId, nsecs_t downTime) {
293*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
294*38e8c45fSAndroid Build Coastguard Worker mLastDownTimes[deviceId] = downTime;
295*38e8c45fSAndroid Build Coastguard Worker mClassifications[deviceId] = MotionClassification::NONE;
296*38e8c45fSAndroid Build Coastguard Worker }
297*38e8c45fSAndroid Build Coastguard Worker
clearDeviceState(int32_t deviceId)298*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::clearDeviceState(int32_t deviceId) {
299*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
300*38e8c45fSAndroid Build Coastguard Worker mClassifications.erase(deviceId);
301*38e8c45fSAndroid Build Coastguard Worker mLastDownTimes.erase(deviceId);
302*38e8c45fSAndroid Build Coastguard Worker }
303*38e8c45fSAndroid Build Coastguard Worker
classify(const NotifyMotionArgs & args)304*38e8c45fSAndroid Build Coastguard Worker MotionClassification MotionClassifier::classify(const NotifyMotionArgs& args) {
305*38e8c45fSAndroid Build Coastguard Worker if ((args.action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN) {
306*38e8c45fSAndroid Build Coastguard Worker updateLastDownTime(args.deviceId, args.downTime);
307*38e8c45fSAndroid Build Coastguard Worker }
308*38e8c45fSAndroid Build Coastguard Worker
309*38e8c45fSAndroid Build Coastguard Worker enqueueEvent(args);
310*38e8c45fSAndroid Build Coastguard Worker return getClassification(args.deviceId);
311*38e8c45fSAndroid Build Coastguard Worker }
312*38e8c45fSAndroid Build Coastguard Worker
reset()313*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::reset() {
314*38e8c45fSAndroid Build Coastguard Worker mEvents.clear();
315*38e8c45fSAndroid Build Coastguard Worker mEvents.push(ClassifierEvent::createHalResetEvent());
316*38e8c45fSAndroid Build Coastguard Worker }
317*38e8c45fSAndroid Build Coastguard Worker
318*38e8c45fSAndroid Build Coastguard Worker /**
319*38e8c45fSAndroid Build Coastguard Worker * Per-device reset. Clear the outstanding events that are going to be sent to HAL.
320*38e8c45fSAndroid Build Coastguard Worker * Request InputProcessor thread to call resetDevice for this particular device.
321*38e8c45fSAndroid Build Coastguard Worker */
reset(const NotifyDeviceResetArgs & args)322*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::reset(const NotifyDeviceResetArgs& args) {
323*38e8c45fSAndroid Build Coastguard Worker int32_t deviceId = args.deviceId;
324*38e8c45fSAndroid Build Coastguard Worker // Clear the pending events right away, to avoid unnecessary work done by the HAL.
325*38e8c45fSAndroid Build Coastguard Worker mEvents.erase_if([deviceId](const ClassifierEvent& event) {
326*38e8c45fSAndroid Build Coastguard Worker std::optional<int32_t> eventDeviceId = event.getDeviceId();
327*38e8c45fSAndroid Build Coastguard Worker return eventDeviceId && (*eventDeviceId == deviceId);
328*38e8c45fSAndroid Build Coastguard Worker });
329*38e8c45fSAndroid Build Coastguard Worker enqueueEvent(args);
330*38e8c45fSAndroid Build Coastguard Worker }
331*38e8c45fSAndroid Build Coastguard Worker
dump(std::string & dump)332*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::dump(std::string& dump) {
333*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
334*38e8c45fSAndroid Build Coastguard Worker dump += StringPrintf(INDENT2 "mService connected: %s\n", mService ? "true" : "false");
335*38e8c45fSAndroid Build Coastguard Worker dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n", mEvents.size(), MAX_EVENTS);
336*38e8c45fSAndroid Build Coastguard Worker dump += INDENT2 "mClassifications, mLastDownTimes:\n";
337*38e8c45fSAndroid Build Coastguard Worker dump += INDENT3 "Device Id\tClassification\tLast down time";
338*38e8c45fSAndroid Build Coastguard Worker // Combine mClassifications and mLastDownTimes into a single table.
339*38e8c45fSAndroid Build Coastguard Worker // Create a superset of device ids.
340*38e8c45fSAndroid Build Coastguard Worker std::unordered_set<int32_t> deviceIds;
341*38e8c45fSAndroid Build Coastguard Worker std::for_each(mClassifications.begin(), mClassifications.end(),
342*38e8c45fSAndroid Build Coastguard Worker [&deviceIds](auto pair) { deviceIds.insert(pair.first); });
343*38e8c45fSAndroid Build Coastguard Worker std::for_each(mLastDownTimes.begin(), mLastDownTimes.end(),
344*38e8c45fSAndroid Build Coastguard Worker [&deviceIds](auto pair) { deviceIds.insert(pair.first); });
345*38e8c45fSAndroid Build Coastguard Worker for (int32_t deviceId : deviceIds) {
346*38e8c45fSAndroid Build Coastguard Worker const MotionClassification classification =
347*38e8c45fSAndroid Build Coastguard Worker getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
348*38e8c45fSAndroid Build Coastguard Worker const nsecs_t downTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
349*38e8c45fSAndroid Build Coastguard Worker dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64, deviceId,
350*38e8c45fSAndroid Build Coastguard Worker motionClassificationToString(classification), downTime);
351*38e8c45fSAndroid Build Coastguard Worker }
352*38e8c45fSAndroid Build Coastguard Worker }
353*38e8c45fSAndroid Build Coastguard Worker
monitor()354*38e8c45fSAndroid Build Coastguard Worker void MotionClassifier::monitor() {
355*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
356*38e8c45fSAndroid Build Coastguard Worker if (mService) {
357*38e8c45fSAndroid Build Coastguard Worker // Ping the HAL service to ensure it is alive and not blocked.
358*38e8c45fSAndroid Build Coastguard Worker const binder_status_t status = AIBinder_ping(mService->asBinder().get());
359*38e8c45fSAndroid Build Coastguard Worker if (status != STATUS_OK) {
360*38e8c45fSAndroid Build Coastguard Worker ALOGW("IInputProcessor HAL is not responding; binder ping result: %s",
361*38e8c45fSAndroid Build Coastguard Worker AStatus_getDescription(AStatus_fromStatus(status)));
362*38e8c45fSAndroid Build Coastguard Worker }
363*38e8c45fSAndroid Build Coastguard Worker }
364*38e8c45fSAndroid Build Coastguard Worker }
365*38e8c45fSAndroid Build Coastguard Worker
366*38e8c45fSAndroid Build Coastguard Worker // --- InputProcessor ---
367*38e8c45fSAndroid Build Coastguard Worker
InputProcessor(InputListenerInterface & listener)368*38e8c45fSAndroid Build Coastguard Worker InputProcessor::InputProcessor(InputListenerInterface& listener) : mQueuedListener(listener) {}
369*38e8c45fSAndroid Build Coastguard Worker
onBinderDied(void * cookie)370*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::onBinderDied(void* cookie) {
371*38e8c45fSAndroid Build Coastguard Worker InputProcessor* processor = static_cast<InputProcessor*>(cookie);
372*38e8c45fSAndroid Build Coastguard Worker if (processor == nullptr) {
373*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("Cookie is not valid");
374*38e8c45fSAndroid Build Coastguard Worker return;
375*38e8c45fSAndroid Build Coastguard Worker }
376*38e8c45fSAndroid Build Coastguard Worker processor->setMotionClassifierEnabled(false);
377*38e8c45fSAndroid Build Coastguard Worker }
378*38e8c45fSAndroid Build Coastguard Worker
setMotionClassifierEnabled(bool enabled)379*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::setMotionClassifierEnabled(bool enabled) {
380*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
381*38e8c45fSAndroid Build Coastguard Worker if (enabled) {
382*38e8c45fSAndroid Build Coastguard Worker ALOGI("Enabling motion classifier");
383*38e8c45fSAndroid Build Coastguard Worker if (mInitializeMotionClassifier.valid()) {
384*38e8c45fSAndroid Build Coastguard Worker scoped_unlock unlock(mLock);
385*38e8c45fSAndroid Build Coastguard Worker std::future_status status = mInitializeMotionClassifier.wait_for(5s);
386*38e8c45fSAndroid Build Coastguard Worker if (status != std::future_status::ready) {
387*38e8c45fSAndroid Build Coastguard Worker /**
388*38e8c45fSAndroid Build Coastguard Worker * We don't have a better option here than to crash. We can't stop the thread,
389*38e8c45fSAndroid Build Coastguard Worker * and we can't continue because 'mInitializeMotionClassifier' will block in its
390*38e8c45fSAndroid Build Coastguard Worker * destructor.
391*38e8c45fSAndroid Build Coastguard Worker */
392*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("The thread to load IInputProcessor is stuck!");
393*38e8c45fSAndroid Build Coastguard Worker }
394*38e8c45fSAndroid Build Coastguard Worker }
395*38e8c45fSAndroid Build Coastguard Worker mInitializeMotionClassifier = std::async(std::launch::async, [this] {
396*38e8c45fSAndroid Build Coastguard Worker setCurrentThreadName("Create MotionClassifier");
397*38e8c45fSAndroid Build Coastguard Worker std::shared_ptr<IInputProcessor> service = getService();
398*38e8c45fSAndroid Build Coastguard Worker if (service == nullptr) {
399*38e8c45fSAndroid Build Coastguard Worker // Keep the MotionClassifier null, no service was found
400*38e8c45fSAndroid Build Coastguard Worker return;
401*38e8c45fSAndroid Build Coastguard Worker }
402*38e8c45fSAndroid Build Coastguard Worker { // acquire lock
403*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock threadLock(mLock);
404*38e8c45fSAndroid Build Coastguard Worker mHalDeathRecipient =
405*38e8c45fSAndroid Build Coastguard Worker std::make_unique<ScopedDeathRecipient>(onBinderDied, /*cookie=*/this);
406*38e8c45fSAndroid Build Coastguard Worker mHalDeathRecipient->linkToDeath(service->asBinder().get());
407*38e8c45fSAndroid Build Coastguard Worker setMotionClassifierLocked(MotionClassifier::create(std::move(service)));
408*38e8c45fSAndroid Build Coastguard Worker } // release lock
409*38e8c45fSAndroid Build Coastguard Worker });
410*38e8c45fSAndroid Build Coastguard Worker } else {
411*38e8c45fSAndroid Build Coastguard Worker ALOGI("Disabling motion classifier");
412*38e8c45fSAndroid Build Coastguard Worker setMotionClassifierLocked(nullptr);
413*38e8c45fSAndroid Build Coastguard Worker }
414*38e8c45fSAndroid Build Coastguard Worker }
415*38e8c45fSAndroid Build Coastguard Worker
notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs & args)416*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) {
417*38e8c45fSAndroid Build Coastguard Worker // pass through
418*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notify(args);
419*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
420*38e8c45fSAndroid Build Coastguard Worker }
421*38e8c45fSAndroid Build Coastguard Worker
notifyKey(const NotifyKeyArgs & args)422*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifyKey(const NotifyKeyArgs& args) {
423*38e8c45fSAndroid Build Coastguard Worker // pass through
424*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyKey(args);
425*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
426*38e8c45fSAndroid Build Coastguard Worker }
427*38e8c45fSAndroid Build Coastguard Worker
notifyMotion(const NotifyMotionArgs & args)428*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifyMotion(const NotifyMotionArgs& args) {
429*38e8c45fSAndroid Build Coastguard Worker { // acquire lock
430*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
431*38e8c45fSAndroid Build Coastguard Worker // MotionClassifier is only used for touch events, for now
432*38e8c45fSAndroid Build Coastguard Worker const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(args);
433*38e8c45fSAndroid Build Coastguard Worker if (!sendToMotionClassifier) {
434*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyMotion(args);
435*38e8c45fSAndroid Build Coastguard Worker } else {
436*38e8c45fSAndroid Build Coastguard Worker NotifyMotionArgs newArgs(args);
437*38e8c45fSAndroid Build Coastguard Worker const MotionClassification newClassification = mMotionClassifier->classify(newArgs);
438*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(args.classification != MotionClassification::NONE &&
439*38e8c45fSAndroid Build Coastguard Worker newClassification != MotionClassification::NONE,
440*38e8c45fSAndroid Build Coastguard Worker "Conflicting classifications %s (new) and %s (old)!",
441*38e8c45fSAndroid Build Coastguard Worker motionClassificationToString(newClassification),
442*38e8c45fSAndroid Build Coastguard Worker motionClassificationToString(args.classification));
443*38e8c45fSAndroid Build Coastguard Worker newArgs.classification = newClassification;
444*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyMotion(newArgs);
445*38e8c45fSAndroid Build Coastguard Worker }
446*38e8c45fSAndroid Build Coastguard Worker } // release lock
447*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
448*38e8c45fSAndroid Build Coastguard Worker }
449*38e8c45fSAndroid Build Coastguard Worker
notifySensor(const NotifySensorArgs & args)450*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifySensor(const NotifySensorArgs& args) {
451*38e8c45fSAndroid Build Coastguard Worker // pass through
452*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifySensor(args);
453*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
454*38e8c45fSAndroid Build Coastguard Worker }
455*38e8c45fSAndroid Build Coastguard Worker
notifyVibratorState(const NotifyVibratorStateArgs & args)456*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifyVibratorState(const NotifyVibratorStateArgs& args) {
457*38e8c45fSAndroid Build Coastguard Worker // pass through
458*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyVibratorState(args);
459*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
460*38e8c45fSAndroid Build Coastguard Worker }
461*38e8c45fSAndroid Build Coastguard Worker
notifySwitch(const NotifySwitchArgs & args)462*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifySwitch(const NotifySwitchArgs& args) {
463*38e8c45fSAndroid Build Coastguard Worker // pass through
464*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifySwitch(args);
465*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
466*38e8c45fSAndroid Build Coastguard Worker }
467*38e8c45fSAndroid Build Coastguard Worker
notifyDeviceReset(const NotifyDeviceResetArgs & args)468*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
469*38e8c45fSAndroid Build Coastguard Worker { // acquire lock
470*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
471*38e8c45fSAndroid Build Coastguard Worker if (mMotionClassifier) {
472*38e8c45fSAndroid Build Coastguard Worker mMotionClassifier->reset(args);
473*38e8c45fSAndroid Build Coastguard Worker }
474*38e8c45fSAndroid Build Coastguard Worker } // release lock
475*38e8c45fSAndroid Build Coastguard Worker
476*38e8c45fSAndroid Build Coastguard Worker // continue to next stage
477*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyDeviceReset(args);
478*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
479*38e8c45fSAndroid Build Coastguard Worker }
480*38e8c45fSAndroid Build Coastguard Worker
notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs & args)481*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) {
482*38e8c45fSAndroid Build Coastguard Worker // pass through
483*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.notifyPointerCaptureChanged(args);
484*38e8c45fSAndroid Build Coastguard Worker mQueuedListener.flush();
485*38e8c45fSAndroid Build Coastguard Worker }
486*38e8c45fSAndroid Build Coastguard Worker
setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> motionClassifier)487*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::setMotionClassifierLocked(
488*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
489*38e8c45fSAndroid Build Coastguard Worker if (motionClassifier == nullptr) {
490*38e8c45fSAndroid Build Coastguard Worker // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath.
491*38e8c45fSAndroid Build Coastguard Worker // We can't call 'unlink' here because we don't have the binder handle.
492*38e8c45fSAndroid Build Coastguard Worker mHalDeathRecipient = nullptr;
493*38e8c45fSAndroid Build Coastguard Worker }
494*38e8c45fSAndroid Build Coastguard Worker mMotionClassifier = std::move(motionClassifier);
495*38e8c45fSAndroid Build Coastguard Worker }
496*38e8c45fSAndroid Build Coastguard Worker
dump(std::string & dump)497*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::dump(std::string& dump) {
498*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
499*38e8c45fSAndroid Build Coastguard Worker dump += "Input Processor State:\n";
500*38e8c45fSAndroid Build Coastguard Worker dump += INDENT1 "Motion Classifier:\n";
501*38e8c45fSAndroid Build Coastguard Worker if (mMotionClassifier) {
502*38e8c45fSAndroid Build Coastguard Worker mMotionClassifier->dump(dump);
503*38e8c45fSAndroid Build Coastguard Worker } else {
504*38e8c45fSAndroid Build Coastguard Worker dump += INDENT2 "<nullptr>";
505*38e8c45fSAndroid Build Coastguard Worker }
506*38e8c45fSAndroid Build Coastguard Worker dump += "\n";
507*38e8c45fSAndroid Build Coastguard Worker }
508*38e8c45fSAndroid Build Coastguard Worker
monitor()509*38e8c45fSAndroid Build Coastguard Worker void InputProcessor::monitor() {
510*38e8c45fSAndroid Build Coastguard Worker std::scoped_lock lock(mLock);
511*38e8c45fSAndroid Build Coastguard Worker if (mMotionClassifier) mMotionClassifier->monitor();
512*38e8c45fSAndroid Build Coastguard Worker }
513*38e8c45fSAndroid Build Coastguard Worker
~InputProcessor()514*38e8c45fSAndroid Build Coastguard Worker InputProcessor::~InputProcessor() {}
515*38e8c45fSAndroid Build Coastguard Worker
516*38e8c45fSAndroid Build Coastguard Worker } // namespace android
517