blob: 261e0125bf4920962704ef733bc7ed45250ad1a9 [file] [log] [blame]
Siarhei Vishniakou473174e2017-12-27 16:44:42 -08001/*
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#ifndef _UI_INPUT_CLASSIFIER_H
18#define _UI_INPUT_CLASSIFIER_H
19
Siarhei Vishniakou61291d42019-02-11 18:13:20 -080020#include <android-base/thread_annotations.h>
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080021#include <future>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080022#include <thread>
Siarhei Vishniakou16523972020-03-04 17:48:39 -080023#include <unordered_map>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080024
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080025#include <aidl/android/hardware/input/processor/IInputProcessor.h>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080026#include "BlockingQueue.h"
27#include "InputListener.h"
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080028namespace android {
29
30enum class ClassifierEventType : uint8_t {
31 MOTION = 0,
32 DEVICE_RESET = 1,
33 HAL_RESET = 2,
34 EXIT = 3,
35};
36
37struct ClassifierEvent {
38 ClassifierEventType type;
39 std::unique_ptr<NotifyArgs> args;
40
41 ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args);
42 ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args);
43 ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args);
44 ClassifierEvent(ClassifierEvent&& other);
45 ClassifierEvent& operator=(ClassifierEvent&& other);
46
47 // Convenience function to create a HAL_RESET event
48 static ClassifierEvent createHalResetEvent();
49 // Convenience function to create an EXIT event
50 static ClassifierEvent createExitEvent();
51
52 std::optional<int32_t> getDeviceId() const;
53};
54
55// --- Interfaces ---
56
57/**
58 * Interface for adding a MotionClassification to NotifyMotionArgs.
59 *
60 * To implement, override the classify function.
61 */
62class MotionClassifierInterface {
63public:
Siarhei Vishniakou98996032022-08-03 11:54:47 -070064 MotionClassifierInterface() {}
65 virtual ~MotionClassifierInterface() {}
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080066 /**
67 * Based on the motion event described by NotifyMotionArgs,
68 * provide a MotionClassification for the current gesture.
69 */
70 virtual MotionClassification classify(const NotifyMotionArgs& args) = 0;
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -080071 /**
72 * Reset all internal HAL state.
73 */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080074 virtual void reset() = 0;
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -080075 /**
76 * Reset HAL state for a specific device.
77 */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080078 virtual void reset(const NotifyDeviceResetArgs& args) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080079
80 /**
Prabir Pradhand7740d62022-07-01 17:54:18 +000081 * Dump the state of the motion classifier.
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080082 */
83 virtual void dump(std::string& dump) = 0;
Prabir Pradhand7740d62022-07-01 17:54:18 +000084
85 /**
86 * Called by the heartbeat to ensure the HAL is still processing normally.
87 */
88 virtual void monitor() = 0;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080089};
90
91/**
92 * Base interface for an InputListener stage.
93 * Provides classification to events.
94 */
Siarhei Vishniakou98996032022-08-03 11:54:47 -070095class InputProcessorInterface : public InputListenerInterface {
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080096public:
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -070097 virtual void setMotionClassifierEnabled(bool enabled) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080098 /**
99 * Dump the state of the input classifier.
100 * This method may be called on any thread (usually by the input manager).
101 */
102 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700103
Prabir Pradhand7740d62022-07-01 17:54:18 +0000104 /** Called by the heartbeat to ensure that the classifier has not deadlocked. */
Siarhei Vishniakou9f330c52022-05-17 05:03:42 -0700105 virtual void monitor() = 0;
106
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700107 InputProcessorInterface() {}
108 virtual ~InputProcessorInterface() {}
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800109};
110
111// --- Implementations ---
112
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800113class ScopedDeathRecipient {
114public:
115 explicit ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied, void* cookie);
116 ScopedDeathRecipient(const ScopedDeathRecipient&) = delete;
117 ScopedDeathRecipient& operator=(ScopedDeathRecipient const&) = delete;
118 void linkToDeath(AIBinder* binder);
119 ~ScopedDeathRecipient();
120
121private:
122 AIBinder_DeathRecipient* mRecipient;
123 void* mCookie;
124};
125
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800126/**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700127 * Implementation of MotionClassifierInterface that calls the InputProcessor HAL
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800128 * in order to determine the classification for the current gesture.
129 *
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700130 * The InputProcessor HAL may keep track of the entire gesture in order to determine
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800131 * the classification, and may be hardware-specific. It may use the data in
132 * NotifyMotionArgs::videoFrames field to drive the classification decisions.
133 * The HAL is called from a separate thread.
134 */
Greg Kaiser04b3a052019-01-29 07:10:14 -0800135class MotionClassifier final : public MotionClassifierInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800136public:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800137 /*
138 * Create an instance of MotionClassifier.
139 * The death recipient, if provided, will be subscribed to the HAL death.
140 * The death recipient could be used to destroy MotionClassifier.
141 *
142 * This function should be called asynchronously, because getService takes a long time.
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800143 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800144 static std::unique_ptr<MotionClassifierInterface> create(
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800145 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800146
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800147 ~MotionClassifier();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700148
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800149 /**
150 * Classifies events asynchronously; that is, it doesn't block events on a classification,
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800151 * but instead sends them over to the classifier HAL. After a classification of a specific
152 * event is determined, MotionClassifier then marks the next event in the stream with this
153 * classification.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800154 *
155 * Therefore, it is acceptable to have the classifications be delayed by 1-2 events
156 * in a particular gesture.
157 */
158 virtual MotionClassification classify(const NotifyMotionArgs& args) override;
159 virtual void reset() override;
160 virtual void reset(const NotifyDeviceResetArgs& args) override;
161
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800162 virtual void dump(std::string& dump) override;
Prabir Pradhand7740d62022-07-01 17:54:18 +0000163 virtual void monitor() override;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800164
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800165private:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800166 friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
167 explicit MotionClassifier(
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800168 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700169
Prabir Pradhand7740d62022-07-01 17:54:18 +0000170 /** The events that need to be sent to the HAL. */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800171 BlockingQueue<ClassifierEvent> mEvents;
172 /**
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800173 * Add an event to the queue mEvents.
174 */
175 void enqueueEvent(ClassifierEvent&& event);
176 /**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700177 * Thread that will communicate with InputProcessor HAL.
178 * This should be the only thread that communicates with InputProcessor HAL,
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800179 * because this thread is allowed to block on the HAL calls.
180 */
181 std::thread mHalThread;
182 /**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700183 * Process events and call the InputProcessor HAL
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800184 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800185 void processEvents();
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800186 /**
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800187 * Access to the InputProcessor HAL. May be null if init() hasn't completed yet.
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700188 * When init() successfully completes, mService is guaranteed to remain non-null and to not
189 * change its value until MotionClassifier is destroyed.
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700190 * This variable is *not* guarded by mLock in the InputProcessor thread, because
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700191 * that thread knows exactly when this variable is initialized.
192 * When accessed in any other thread, mService is checked for nullness with a lock.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800193 */
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800194 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> mService;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800195 std::mutex mLock;
196 /**
197 * Per-device input classifications. Should only be accessed using the
198 * getClassification / setClassification methods.
199 */
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700200 std::unordered_map<int32_t /*deviceId*/, MotionClassification> mClassifications
201 GUARDED_BY(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800202 /**
203 * Set the current classification for a given device.
204 */
205 void setClassification(int32_t deviceId, MotionClassification classification);
206 /**
207 * Get the current classification for a given device.
208 */
209 MotionClassification getClassification(int32_t deviceId);
210 void updateClassification(int32_t deviceId, nsecs_t eventTime,
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700211 MotionClassification classification);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800212 /**
213 * Clear all current classifications
214 */
215 void clearClassifications();
216 /**
217 * Per-device times when the last ACTION_DOWN was received.
218 * Used to reject late classifications that do not belong to the current gesture.
219 *
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700220 * Accessed indirectly by both InputProcessor thread and the thread that receives notifyMotion.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800221 */
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800222 std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
223
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800224 void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800225
Siarhei Vishniakoue3021d72020-02-28 15:25:41 -0800226 void clearDeviceState(int32_t deviceId);
227
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800228 /**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700229 * Exit the InputProcessor HAL thread.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800230 * Useful for tests to ensure proper cleanup.
231 */
232 void requestExit();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700233 /**
234 * Return string status of mService
235 */
236 const char* getServiceStatus() REQUIRES(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800237};
238
239/**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700240 * Implementation of the InputProcessorInterface.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800241 * Represents a separate stage of input processing. All of the input events go through this stage.
242 * Acts as a passthrough for all input events except for motion events.
243 * The events of motion type are sent to MotionClassifier.
244 */
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700245class InputProcessor : public InputProcessorInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800246public:
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700247 explicit InputProcessor(InputListenerInterface& listener);
Siarhei Vishniakou45bb0882019-02-04 14:25:28 -0800248
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800249 void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
250 void notifyKey(const NotifyKeyArgs* args) override;
251 void notifyMotion(const NotifyMotionArgs* args) override;
252 void notifySwitch(const NotifySwitchArgs* args) override;
253 void notifySensor(const NotifySensorArgs* args) override;
254 void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
255 void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
Prabir Pradhan7e186182020-11-10 13:56:45 -0800256 void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800257
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800258 void dump(std::string& dump) override;
Siarhei Vishniakou9f330c52022-05-17 05:03:42 -0700259 void monitor() override;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800260
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700261 ~InputProcessor();
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800262
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700263 // Called from InputManager
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800264 void setMotionClassifierEnabled(bool enabled) override;
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700265
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800266private:
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800267 // Protect access to mMotionClassifier, since it may become null via a hidl callback
268 std::mutex mLock;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800269 // The next stage to pass input events to
Siarhei Vishniakou9f330c52022-05-17 05:03:42 -0700270 QueuedInputListener mQueuedListener;
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800271
272 std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800273 std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);
274
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800275 /**
276 * Set the value of mMotionClassifier.
277 * This is called from 2 different threads:
278 * 1) mInitializeMotionClassifierThread, when we have constructed a MotionClassifier
279 * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause
280 * mMotionClassifier to become nullptr.
281 */
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800282 void setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> motionClassifier)
283 REQUIRES(mLock);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800284
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800285 static void onBinderDied(void* cookie);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800286
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800287 std::unique_ptr<ScopedDeathRecipient> mHalDeathRecipient GUARDED_BY(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800288};
289
290} // namespace android
Greg Kaiser04b3a052019-01-29 07:10:14 -0800291#endif