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