blob: 7a00a2dae8270ce800448a9655fa8358aee96254 [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
Prabir Pradhan48108662022-09-09 21:22:04 +000017#pragma once
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080018
Siarhei Vishniakou61291d42019-02-11 18:13:20 -080019#include <android-base/thread_annotations.h>
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080020#include <future>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080021#include <thread>
Siarhei Vishniakou16523972020-03-04 17:48:39 -080022#include <unordered_map>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080023
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -080024#include <aidl/android/hardware/input/processor/IInputProcessor.h>
Siarhei Vishniakou8c5f7be2024-05-01 22:48:16 +000025#include <input/BlockingQueue.h>
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080026#include "InputListener.h"
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080027namespace android {
28
29enum class ClassifierEventType : uint8_t {
30 MOTION = 0,
31 DEVICE_RESET = 1,
32 HAL_RESET = 2,
33 EXIT = 3,
34};
35
36struct ClassifierEvent {
37 ClassifierEventType type;
Siarhei Vishniakou096257c2022-09-15 17:02:20 -070038 std::optional<NotifyArgs> args;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080039
Siarhei Vishniakou096257c2022-09-15 17:02:20 -070040 ClassifierEvent(ClassifierEventType type, std::optional<NotifyArgs> args);
41 ClassifierEvent(const NotifyMotionArgs& args);
42 ClassifierEvent(const NotifyDeviceResetArgs& args);
43 ClassifierEvent(ClassifierEvent&& other) = default;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080044 ClassifierEvent& operator=(ClassifierEvent&& other);
45
46 // Convenience function to create a HAL_RESET event
47 static ClassifierEvent createHalResetEvent();
48 // Convenience function to create an EXIT event
49 static ClassifierEvent createExitEvent();
50
51 std::optional<int32_t> getDeviceId() const;
52};
53
54// --- Interfaces ---
55
56/**
57 * Interface for adding a MotionClassification to NotifyMotionArgs.
58 *
59 * To implement, override the classify function.
60 */
61class MotionClassifierInterface {
62public:
Siarhei Vishniakou98996032022-08-03 11:54:47 -070063 MotionClassifierInterface() {}
64 virtual ~MotionClassifierInterface() {}
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080065 /**
66 * Based on the motion event described by NotifyMotionArgs,
67 * provide a MotionClassification for the current gesture.
68 */
69 virtual MotionClassification classify(const NotifyMotionArgs& args) = 0;
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -080070 /**
71 * Reset all internal HAL state.
72 */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080073 virtual void reset() = 0;
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -080074 /**
75 * Reset HAL state for a specific device.
76 */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080077 virtual void reset(const NotifyDeviceResetArgs& args) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080078
79 /**
Prabir Pradhand7740d62022-07-01 17:54:18 +000080 * Dump the state of the motion classifier.
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080081 */
82 virtual void dump(std::string& dump) = 0;
Prabir Pradhand7740d62022-07-01 17:54:18 +000083
84 /**
85 * Called by the heartbeat to ensure the HAL is still processing normally.
86 */
87 virtual void monitor() = 0;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -080088};
89
90/**
91 * Base interface for an InputListener stage.
92 * Provides classification to events.
93 */
Siarhei Vishniakou98996032022-08-03 11:54:47 -070094class InputProcessorInterface : public InputListenerInterface {
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080095public:
Siarhei Vishniakouc9ac19e2020-03-19 11:55:01 -070096 virtual void setMotionClassifierEnabled(bool enabled) = 0;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -080097 /**
98 * Dump the state of the input classifier.
99 * This method may be called on any thread (usually by the input manager).
100 */
101 virtual void dump(std::string& dump) = 0;
Siarhei Vishniakou18050092021-09-01 13:32:49 -0700102
Prabir Pradhand7740d62022-07-01 17:54:18 +0000103 /** Called by the heartbeat to ensure that the classifier has not deadlocked. */
Siarhei Vishniakou9f330c52022-05-17 05:03:42 -0700104 virtual void monitor() = 0;
105
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700106 InputProcessorInterface() {}
107 virtual ~InputProcessorInterface() {}
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800108};
109
110// --- Implementations ---
111
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800112class ScopedDeathRecipient {
113public:
114 explicit ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied, void* cookie);
115 ScopedDeathRecipient(const ScopedDeathRecipient&) = delete;
116 ScopedDeathRecipient& operator=(ScopedDeathRecipient const&) = delete;
117 void linkToDeath(AIBinder* binder);
118 ~ScopedDeathRecipient();
119
120private:
121 AIBinder_DeathRecipient* mRecipient;
122 void* mCookie;
123};
124
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800125/**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700126 * Implementation of MotionClassifierInterface that calls the InputProcessor HAL
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800127 * in order to determine the classification for the current gesture.
128 *
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700129 * The InputProcessor HAL may keep track of the entire gesture in order to determine
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800130 * the classification, and may be hardware-specific. It may use the data in
131 * NotifyMotionArgs::videoFrames field to drive the classification decisions.
132 * The HAL is called from a separate thread.
133 */
Greg Kaiser04b3a052019-01-29 07:10:14 -0800134class MotionClassifier final : public MotionClassifierInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800135public:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800136 /*
137 * Create an instance of MotionClassifier.
138 * The death recipient, if provided, will be subscribed to the HAL death.
139 * The death recipient could be used to destroy MotionClassifier.
140 *
141 * This function should be called asynchronously, because getService takes a long time.
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800142 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800143 static std::unique_ptr<MotionClassifierInterface> create(
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800144 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800145
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800146 ~MotionClassifier();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700147
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800148 /**
149 * Classifies events asynchronously; that is, it doesn't block events on a classification,
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800150 * but instead sends them over to the classifier HAL. After a classification of a specific
151 * event is determined, MotionClassifier then marks the next event in the stream with this
152 * classification.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800153 *
154 * Therefore, it is acceptable to have the classifications be delayed by 1-2 events
155 * in a particular gesture.
156 */
157 virtual MotionClassification classify(const NotifyMotionArgs& args) override;
158 virtual void reset() override;
159 virtual void reset(const NotifyDeviceResetArgs& args) override;
160
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800161 virtual void dump(std::string& dump) override;
Prabir Pradhand7740d62022-07-01 17:54:18 +0000162 virtual void monitor() override;
Siarhei Vishniakoua028c442019-02-04 14:33:23 -0800163
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800164private:
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800165 friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
166 explicit MotionClassifier(
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800167 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700168
Prabir Pradhand7740d62022-07-01 17:54:18 +0000169 /** The events that need to be sent to the HAL. */
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800170 BlockingQueue<ClassifierEvent> mEvents;
171 /**
Siarhei Vishniakou15b66d12019-02-04 14:27:29 -0800172 * Add an event to the queue mEvents.
173 */
174 void enqueueEvent(ClassifierEvent&& event);
175 /**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700176 * Thread that will communicate with InputProcessor HAL.
177 * This should be the only thread that communicates with InputProcessor HAL,
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800178 * because this thread is allowed to block on the HAL calls.
179 */
180 std::thread mHalThread;
181 /**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700182 * Process events and call the InputProcessor HAL
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800183 */
Siarhei Vishniakou16523972020-03-04 17:48:39 -0800184 void processEvents();
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800185 /**
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800186 * Access to the InputProcessor HAL. May be null if init() hasn't completed yet.
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700187 * When init() successfully completes, mService is guaranteed to remain non-null and to not
188 * change its value until MotionClassifier is destroyed.
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700189 * This variable is *not* guarded by mLock in the InputProcessor thread, because
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700190 * that thread knows exactly when this variable is initialized.
191 * When accessed in any other thread, mService is checked for nullness with a lock.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800192 */
Siarhei Vishniakou34d6fef2022-02-01 19:03:45 -0800193 std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> mService;
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800194 std::mutex mLock;
195 /**
196 * Per-device input classifications. Should only be accessed using the
197 * getClassification / setClassification methods.
198 */
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700199 std::unordered_map<int32_t /*deviceId*/, MotionClassification> mClassifications
200 GUARDED_BY(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800201 /**
202 * Set the current classification for a given device.
203 */
204 void setClassification(int32_t deviceId, MotionClassification classification);
205 /**
206 * Get the current classification for a given device.
207 */
208 MotionClassification getClassification(int32_t deviceId);
209 void updateClassification(int32_t deviceId, nsecs_t eventTime,
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700210 MotionClassification classification);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800211 /**
212 * Clear all current classifications
213 */
214 void clearClassifications();
215 /**
216 * Per-device times when the last ACTION_DOWN was received.
217 * Used to reject late classifications that do not belong to the current gesture.
218 *
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700219 * Accessed indirectly by both InputProcessor thread and the thread that receives notifyMotion.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800220 */
Siarhei Vishniakou61291d42019-02-11 18:13:20 -0800221 std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
222
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800223 void updateLastDownTime(int32_t deviceId, nsecs_t downTime);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800224
Siarhei Vishniakoue3021d72020-02-28 15:25:41 -0800225 void clearDeviceState(int32_t deviceId);
226
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800227 /**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700228 * Exit the InputProcessor HAL thread.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800229 * Useful for tests to ensure proper cleanup.
230 */
231 void requestExit();
Siarhei Vishniakou4bdbb6a2019-04-11 09:42:09 -0700232 /**
233 * Return string status of mService
234 */
235 const char* getServiceStatus() REQUIRES(mLock);
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800236};
237
238/**
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700239 * Implementation of the InputProcessorInterface.
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800240 * Represents a separate stage of input processing. All of the input events go through this stage.
241 * Acts as a passthrough for all input events except for motion events.
242 * The events of motion type are sent to MotionClassifier.
243 */
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700244class InputProcessor : public InputProcessorInterface {
Siarhei Vishniakou473174e2017-12-27 16:44:42 -0800245public:
Siarhei Vishniakou98996032022-08-03 11:54:47 -0700246 explicit InputProcessor(InputListenerInterface& listener);
Siarhei Vishniakou45bb0882019-02-04 14:25:28 -0800247
Prabir Pradhane3da4bb2023-04-05 23:51:23 +0000248 void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
Prabir Pradhan678438e2023-04-13 19:32:51 +0000249 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;
256 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