blob: 56cf76025606ca92e6a33df57a8efa4de4b4459a [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:
64 MotionClassifierInterface() { }
65 virtual ~MotionClassifierInterface() { }
66 /**
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 /**
81 * Dump the state of the motion classifier
82 */
83 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080084};
85
86/**
87 * Base interface for an InputListener stage.
88 * Provides classification to events.
89 */
Siarhei Vishniakou18050092021-09-01 13:32:49 -070090class InputClassifierInterface : public InputListenerInterface {
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080091public:
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -070092 virtual void setMotionClassifierEnabled(bool enabled) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080093 /**
94 * Dump the state of the input classifier.
95 * This method may be called on any thread (usually by the input manager).
96 */
97 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou18050092021-09-01 13:32:49 -070098
Siarhei Vishniakou9f330c52022-05-17 05:03:42 -070099 /* Called by the heatbeat to ensures that the classifier has not deadlocked. */
100 virtual void monitor() = 0;
101
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800102 InputClassifierInterface() { }
103 virtual ~InputClassifierInterface() { }
104};
105
106// --- Implementations ---
107
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800108class ScopedDeathRecipient {
109public:
110 explicit ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied, void* cookie);
111 ScopedDeathRecipient(const ScopedDeathRecipient&) = delete;
112 ScopedDeathRecipient& operator=(ScopedDeathRecipient const&) = delete;
113 void linkToDeath(AIBinder* binder);
114 ~ScopedDeathRecipient();
115
116private:
117 AIBinder_DeathRecipient* mRecipient;
118 void* mCookie;
119};
120
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800121/**
122 * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
123 * in order to determine the classification for the current gesture.
124 *
125 * The InputClassifier HAL may keep track of the entire gesture in order to determine
126 * the classification, and may be hardware-specific. It may use the data in
127 * NotifyMotionArgs::videoFrames field to drive the classification decisions.
128 * The HAL is called from a separate thread.
129 */
Greg Kaiser04b3a052019-01-29 07:10:14 -0800130class MotionClassifier final : public MotionClassifierInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800131public:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800132 /*
133 * Create an instance of MotionClassifier.
134 * The death recipient, if provided, will be subscribed to the HAL death.
135 * The death recipient could be used to destroy MotionClassifier.
136 *
137 * This function should be called asynchronously, because getService takes a long time.
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800138 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800139 static std::unique_ptr<MotionClassifierInterface> create(
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800140 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800141
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800142 ~MotionClassifier();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700143
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800144 /**
145 * Classifies events asynchronously; that is, it doesn't block events on a classification,
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800146 * but instead sends them over to the classifier HAL. After a classification of a specific
147 * event is determined, MotionClassifier then marks the next event in the stream with this
148 * classification.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800149 *
150 * Therefore, it is acceptable to have the classifications be delayed by 1-2 events
151 * in a particular gesture.
152 */
153 virtual MotionClassification classify(const NotifyMotionArgs& args) override;
154 virtual void reset() override;
155 virtual void reset(const NotifyDeviceResetArgs& args) override;
156
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800157 virtual void dump(std::string& dump) override;
158
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800159private:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800160 friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
161 explicit MotionClassifier(
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800162 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700163
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800164 // The events that need to be sent to the HAL.
165 BlockingQueue<ClassifierEvent> mEvents;
166 /**
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800167 * Add an event to the queue mEvents.
168 */
169 void enqueueEvent(ClassifierEvent&& event);
170 /**
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800171 * Thread that will communicate with InputClassifier HAL.
172 * This should be the only thread that communicates with InputClassifier HAL,
173 * because this thread is allowed to block on the HAL calls.
174 */
175 std::thread mHalThread;
176 /**
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800177 * Process events and call the InputClassifier HAL
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800178 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800179 void processEvents();
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800180 /**
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800181 * Access to the InputProcessor HAL. May be null if init() hasn't completed yet.
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700182 * When init() successfully completes, mService is guaranteed to remain non-null and to not
183 * change its value until MotionClassifier is destroyed.
184 * This variable is *not* guarded by mLock in the InputClassifier thread, because
185 * that thread knows exactly when this variable is initialized.
186 * When accessed in any other thread, mService is checked for nullness with a lock.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800187 */
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800188 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> mService;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800189 std::mutex mLock;
190 /**
191 * Per-device input classifications. Should only be accessed using the
192 * getClassification / setClassification methods.
193 */
194 std::unordered_map<int32_t /*deviceId*/, MotionClassification>
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800195 mClassifications GUARDED_BY(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800196 /**
197 * Set the current classification for a given device.
198 */
199 void setClassification(int32_t deviceId, MotionClassification classification);
200 /**
201 * Get the current classification for a given device.
202 */
203 MotionClassification getClassification(int32_t deviceId);
204 void updateClassification(int32_t deviceId, nsecs_t eventTime,
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800205 MotionClassification classification);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800206 /**
207 * Clear all current classifications
208 */
209 void clearClassifications();
210 /**
211 * Per-device times when the last ACTION_DOWN was received.
212 * Used to reject late classifications that do not belong to the current gesture.
213 *
214 * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion.
215 */
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800216 std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
217
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800218 void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800219
Siarhei Vishniakoue3021d72020-02-28 15:25:41 -0800220 void clearDeviceState(int32_t deviceId);
221
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800222 /**
223 * Exit the InputClassifier HAL thread.
224 * Useful for tests to ensure proper cleanup.
225 */
226 void requestExit();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700227 /**
228 * Return string status of mService
229 */
230 const char* getServiceStatus() REQUIRES(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800231};
232
233/**
234 * Implementation of the InputClassifierInterface.
235 * Represents a separate stage of input processing. All of the input events go through this stage.
236 * Acts as a passthrough for all input events except for motion events.
237 * The events of motion type are sent to MotionClassifier.
238 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800239class InputClassifier : public InputClassifierInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800240public:
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700241 explicit InputClassifier(InputListenerInterface& listener);
Siarhei Vishniakou45bb0882019-02-04 14:25:28 -0800242
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800243 void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
244 void notifyKey(const NotifyKeyArgs* args) override;
245 void notifyMotion(const NotifyMotionArgs* args) override;
246 void notifySwitch(const NotifySwitchArgs* args) override;
247 void notifySensor(const NotifySensorArgs* args) override;
248 void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
249 void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
Prabir Pradhan7e186182020-11-10 13:56:45 -0800250 void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800251
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800252 void dump(std::string& dump) override;
Siarhei Vishniakou9f330c52022-05-17 05:03:42 -0700253 void monitor() override;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800254
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800255 ~InputClassifier();
256
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700257 // Called from InputManager
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800258 void setMotionClassifierEnabled(bool enabled) override;
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -0700259
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800260private:
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800261 // Protect access to mMotionClassifier, since it may become null via a hidl callback
262 std::mutex mLock;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800263 // The next stage to pass input events to
Siarhei Vishniakou9f330c52022-05-17 05:03:42 -0700264 QueuedInputListener mQueuedListener;
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800265
266 std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800267 std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);
268
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800269 /**
270 * Set the value of mMotionClassifier.
271 * This is called from 2 different threads:
272 * 1) mInitializeMotionClassifierThread, when we have constructed a MotionClassifier
273 * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause
274 * mMotionClassifier to become nullptr.
275 */
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800276 void setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> motionClassifier)
277 REQUIRES(mLock);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800278
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800279 static void onBinderDied(void* cookie);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800280
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800281 std::unique_ptr<ScopedDeathRecipient> mHalDeathRecipient GUARDED_BY(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800282};
283
284} // namespace android
Greg Kaiser04b3a052019-01-29 07:10:14 -0800285#endif