1 /*
2 * Copyright 2022 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 #pragma once
17
18 #include <map>
19 #include <memory>
20
21 #include <EventHub.h>
22 #include <InputDevice.h>
23 #include <InputMapper.h>
24 #include <InputReader.h>
25 #include <ThreadSafeFuzzedDataProvider.h>
26
27 constexpr size_t kValidTypes[] = {EV_SW,
28 EV_SYN,
29 EV_ABS,
30 EV_KEY,
31 EV_MSC,
32 EV_REL,
33 android::EventHubInterface::DEVICE_ADDED,
34 android::EventHubInterface::DEVICE_REMOVED,
35 android::EventHubInterface::FINISHED_DEVICE_SCAN};
36
37 constexpr size_t kValidCodes[] = {
38 SYN_REPORT,
39 ABS_MT_SLOT,
40 SYN_MT_REPORT,
41 ABS_MT_POSITION_X,
42 ABS_MT_POSITION_Y,
43 ABS_MT_TOUCH_MAJOR,
44 ABS_MT_TOUCH_MINOR,
45 ABS_MT_WIDTH_MAJOR,
46 ABS_MT_WIDTH_MINOR,
47 ABS_MT_ORIENTATION,
48 ABS_MT_TRACKING_ID,
49 ABS_MT_PRESSURE,
50 ABS_MT_DISTANCE,
51 ABS_MT_TOOL_TYPE,
52 MSC_SCAN,
53 REL_X,
54 REL_Y,
55 REL_WHEEL,
56 REL_HWHEEL,
57 BTN_LEFT,
58 BTN_RIGHT,
59 BTN_MIDDLE,
60 BTN_BACK,
61 BTN_SIDE,
62 BTN_FORWARD,
63 BTN_EXTRA,
64 BTN_TASK,
65 };
66
67 constexpr size_t kMaxSize = 256;
68
69 namespace android {
70
71 template<class Fdp>
getFuzzedToolType(Fdp & fdp)72 ToolType getFuzzedToolType(Fdp& fdp) {
73 const int32_t toolType = fdp.template ConsumeIntegralInRange<int32_t>(
74 static_cast<int32_t>(ToolType::ftl_first),
75 static_cast<int32_t>(ToolType::ftl_last));
76 return static_cast<ToolType>(toolType);
77 }
78
79 template <class Fdp>
getFuzzedRawEvent(Fdp & fdp)80 RawEvent getFuzzedRawEvent(Fdp& fdp) {
81 const int32_t type = fdp.ConsumeBool() ? fdp.PickValueInArray(kValidTypes)
82 : fdp.template ConsumeIntegral<int32_t>();
83 const int32_t code = fdp.ConsumeBool() ? fdp.PickValueInArray(kValidCodes)
84 : fdp.template ConsumeIntegral<int32_t>();
85 return RawEvent{
86 .when = fdp.template ConsumeIntegral<nsecs_t>(),
87 .readTime = fdp.template ConsumeIntegral<nsecs_t>(),
88 .deviceId = fdp.template ConsumeIntegral<int32_t>(),
89 .type = type,
90 .code = code,
91 .value = fdp.template ConsumeIntegral<int32_t>(),
92 };
93 }
94
95 class FuzzEventHub : public EventHubInterface {
96 InputDeviceIdentifier mIdentifier;
97 std::vector<TouchVideoFrame> mVideoFrames;
98 PropertyMap mFuzzConfig;
99 std::map<int32_t /* deviceId */, std::map<int /* axis */, RawAbsoluteAxisInfo>> mAxes;
100 std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp;
101
102 public:
FuzzEventHub(std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp)103 FuzzEventHub(std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) : mFdp(std::move(fdp)) {}
~FuzzEventHub()104 ~FuzzEventHub() {}
addProperty(std::string key,std::string value)105 void addProperty(std::string key, std::string value) { mFuzzConfig.addProperty(key, value); }
106
getDeviceClasses(int32_t deviceId)107 ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
108 return ftl::Flags<InputDeviceClass>(mFdp->ConsumeIntegral<uint32_t>());
109 }
getDeviceIdentifier(int32_t deviceId)110 InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
111 return mIdentifier;
112 }
getDeviceControllerNumber(int32_t deviceId)113 int32_t getDeviceControllerNumber(int32_t deviceId) const override {
114 return mFdp->ConsumeIntegral<int32_t>();
115 }
getConfiguration(int32_t deviceId)116 std::optional<PropertyMap> getConfiguration(int32_t deviceId) const override {
117 return mFuzzConfig;
118 }
setAbsoluteAxisInfo(int32_t deviceId,int axis,const RawAbsoluteAxisInfo & axisInfo)119 void setAbsoluteAxisInfo(int32_t deviceId, int axis, const RawAbsoluteAxisInfo& axisInfo) {
120 mAxes[deviceId][axis] = axisInfo;
121 }
getAbsoluteAxisInfo(int32_t deviceId,int axis,RawAbsoluteAxisInfo * outAxisInfo)122 status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
123 RawAbsoluteAxisInfo* outAxisInfo) const override {
124 if (auto deviceAxesIt = mAxes.find(deviceId); deviceAxesIt != mAxes.end()) {
125 const std::map<int, RawAbsoluteAxisInfo>& deviceAxes = deviceAxesIt->second;
126 if (auto axisInfoIt = deviceAxes.find(axis); axisInfoIt != deviceAxes.end()) {
127 *outAxisInfo = axisInfoIt->second;
128 return OK;
129 }
130 }
131 return mFdp->ConsumeIntegral<status_t>();
132 }
hasRelativeAxis(int32_t deviceId,int axis)133 bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); }
hasInputProperty(int32_t deviceId,int property)134 bool hasInputProperty(int32_t deviceId, int property) const override {
135 return mFdp->ConsumeBool();
136 }
hasMscEvent(int32_t deviceId,int mscEvent)137 bool hasMscEvent(int32_t deviceId, int mscEvent) const override { return mFdp->ConsumeBool(); }
mapKey(int32_t deviceId,int32_t scanCode,int32_t usageCode,int32_t metaState,int32_t * outKeycode,int32_t * outMetaState,uint32_t * outFlags)138 status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
139 int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override {
140 return mFdp->ConsumeIntegral<status_t>();
141 }
mapAxis(int32_t deviceId,int32_t scanCode,AxisInfo * outAxisInfo)142 status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const override {
143 return mFdp->ConsumeIntegral<status_t>();
144 }
setExcludedDevices(const std::vector<std::string> & devices)145 void setExcludedDevices(const std::vector<std::string>& devices) override {}
getEvents(int timeoutMillis)146 std::vector<RawEvent> getEvents(int timeoutMillis) override {
147 std::vector<RawEvent> events;
148 const size_t count = mFdp->ConsumeIntegralInRange<size_t>(0, kMaxSize);
149 for (size_t i = 0; i < count; ++i) {
150 events.push_back(getFuzzedRawEvent(*mFdp));
151 }
152 return events;
153 }
getVideoFrames(int32_t deviceId)154 std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override { return mVideoFrames; }
155
mapSensor(int32_t deviceId,int32_t absCode)156 base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(
157 int32_t deviceId, int32_t absCode) const override {
158 return base::ResultError("Fuzzer", UNKNOWN_ERROR);
159 };
160 // Raw batteries are sysfs power_supply nodes we found from the EventHub device sysfs node,
161 // containing the raw info of the sysfs node structure.
getRawBatteryIds(int32_t deviceId)162 std::vector<int32_t> getRawBatteryIds(int32_t deviceId) const override { return {}; }
getRawBatteryInfo(int32_t deviceId,int32_t BatteryId)163 std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId,
164 int32_t BatteryId) const override {
165 return std::nullopt;
166 };
167
getRawLightIds(int32_t deviceId)168 std::vector<int32_t> getRawLightIds(int32_t deviceId) const override { return {}; };
getRawLightInfo(int32_t deviceId,int32_t lightId)169 std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) const override {
170 return std::nullopt;
171 };
getLightBrightness(int32_t deviceId,int32_t lightId)172 std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override {
173 return std::nullopt;
174 };
setLightBrightness(int32_t deviceId,int32_t lightId,int32_t brightness)175 void setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) override{};
getLightIntensities(int32_t deviceId,int32_t lightId)176 std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities(
177 int32_t deviceId, int32_t lightId) const override {
178 return std::nullopt;
179 };
setLightIntensities(int32_t deviceId,int32_t lightId,std::unordered_map<LightColor,int32_t> intensities)180 void setLightIntensities(int32_t deviceId, int32_t lightId,
181 std::unordered_map<LightColor, int32_t> intensities) override{};
182
getRawLayoutInfo(int32_t deviceId)183 std::optional<RawLayoutInfo> getRawLayoutInfo(int32_t deviceId) const override {
184 return std::nullopt;
185 };
186
getScanCodeState(int32_t deviceId,int32_t scanCode)187 int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override {
188 return mFdp->ConsumeIntegral<int32_t>();
189 }
getKeyCodeState(int32_t deviceId,int32_t keyCode)190 int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override {
191 return mFdp->ConsumeIntegral<int32_t>();
192 }
getSwitchState(int32_t deviceId,int32_t sw)193 int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
194 return mFdp->ConsumeIntegral<int32_t>();
195 }
addKeyRemapping(int32_t deviceId,int32_t fromKeyCode,int32_t toKeyCode)196 void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const override {}
getKeyCodeForKeyLocation(int32_t deviceId,int32_t locationKeyCode)197 int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override {
198 return mFdp->ConsumeIntegral<int32_t>();
199 }
getAbsoluteAxisValue(int32_t deviceId,int32_t axis,int32_t * outValue)200 status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
201 int32_t* outValue) const override {
202 return mFdp->ConsumeIntegral<status_t>();
203 }
getMtSlotValues(int32_t deviceId,int32_t axis,size_t slotCount)204 base::Result<std::vector<int32_t>> getMtSlotValues(int32_t deviceId, int32_t axis,
205 size_t slotCount) const override {
206 if (mFdp->ConsumeBool()) {
207 std::vector<int32_t> outValues(slotCount + 1);
208 for (size_t i = 0; i < outValues.size(); i++) {
209 outValues.push_back(mFdp->ConsumeIntegral<int32_t>());
210 }
211 return std::move(outValues);
212 } else {
213 return base::ResultError("Fuzzer", UNKNOWN_ERROR);
214 }
215 }
markSupportedKeyCodes(int32_t deviceId,const std::vector<int32_t> & keyCodes,uint8_t * outFlags)216 bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes,
217 uint8_t* outFlags) const override {
218 return mFdp->ConsumeBool();
219 }
hasScanCode(int32_t deviceId,int32_t scanCode)220 bool hasScanCode(int32_t deviceId, int32_t scanCode) const override {
221 return mFdp->ConsumeBool();
222 }
hasKeyCode(int32_t deviceId,int32_t keyCode)223 bool hasKeyCode(int32_t deviceId, int32_t keyCode) const override {
224 return mFdp->ConsumeBool();
225 }
hasLed(int32_t deviceId,int32_t led)226 bool hasLed(int32_t deviceId, int32_t led) const override { return mFdp->ConsumeBool(); }
setLedState(int32_t deviceId,int32_t led,bool on)227 void setLedState(int32_t deviceId, int32_t led, bool on) override {}
getVirtualKeyDefinitions(int32_t deviceId,std::vector<VirtualKeyDefinition> & outVirtualKeys)228 void getVirtualKeyDefinitions(
229 int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override {}
getKeyCharacterMap(int32_t deviceId)230 const std::shared_ptr<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const override {
231 return nullptr;
232 }
setKeyboardLayoutOverlay(int32_t deviceId,std::shared_ptr<KeyCharacterMap> map)233 bool setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) override {
234 return mFdp->ConsumeBool();
235 }
vibrate(int32_t deviceId,const VibrationElement & effect)236 void vibrate(int32_t deviceId, const VibrationElement& effect) override {}
cancelVibrate(int32_t deviceId)237 void cancelVibrate(int32_t deviceId) override {}
238
getVibratorIds(int32_t deviceId)239 std::vector<int32_t> getVibratorIds(int32_t deviceId) const override { return {}; };
240
241 /* Query battery level. */
getBatteryCapacity(int32_t deviceId,int32_t batteryId)242 std::optional<int32_t> getBatteryCapacity(int32_t deviceId, int32_t batteryId) const override {
243 return std::nullopt;
244 };
245
246 /* Query battery status. */
getBatteryStatus(int32_t deviceId,int32_t batteryId)247 std::optional<int32_t> getBatteryStatus(int32_t deviceId, int32_t batteryId) const override {
248 return std::nullopt;
249 };
250
requestReopenDevices()251 void requestReopenDevices() override {}
wake()252 void wake() override {}
dump(std::string & dump)253 void dump(std::string& dump) const override {}
monitor()254 void monitor() const override {}
isDeviceEnabled(int32_t deviceId)255 bool isDeviceEnabled(int32_t deviceId) const override { return mFdp->ConsumeBool(); }
enableDevice(int32_t deviceId)256 status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
disableDevice(int32_t deviceId)257 status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); }
sysfsNodeChanged(const std::string & sysfsNodePath)258 void sysfsNodeChanged(const std::string& sysfsNodePath) override {}
259 };
260
261 class FuzzInputReaderPolicy : public InputReaderPolicyInterface {
262 TouchAffineTransformation mTransform;
263 std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp;
264
265 protected:
~FuzzInputReaderPolicy()266 ~FuzzInputReaderPolicy() {}
267
268 public:
FuzzInputReaderPolicy(std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp)269 FuzzInputReaderPolicy(std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp) : mFdp(mFdp) {}
getReaderConfiguration(InputReaderConfiguration * outConfig)270 void getReaderConfiguration(InputReaderConfiguration* outConfig) override {}
notifyInputDevicesChanged(const std::vector<InputDeviceInfo> & inputDevices)271 void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) override {}
getKeyboardLayoutOverlay(const InputDeviceIdentifier & identifier,const std::optional<KeyboardLayoutInfo> layoutInfo)272 std::shared_ptr<KeyCharacterMap> getKeyboardLayoutOverlay(
273 const InputDeviceIdentifier& identifier,
274 const std::optional<KeyboardLayoutInfo> layoutInfo) override {
275 return nullptr;
276 }
getDeviceAlias(const InputDeviceIdentifier & identifier)277 std::string getDeviceAlias(const InputDeviceIdentifier& identifier) {
278 return mFdp->ConsumeRandomLengthString(32);
279 }
getTouchAffineTransformation(const std::string & inputDeviceDescriptor,ui::Rotation surfaceRotation)280 TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
281 ui::Rotation surfaceRotation) override {
282 return mTransform;
283 }
setTouchAffineTransformation(const TouchAffineTransformation t)284 void setTouchAffineTransformation(const TouchAffineTransformation t) { mTransform = t; }
notifyStylusGestureStarted(int32_t,nsecs_t)285 void notifyStylusGestureStarted(int32_t, nsecs_t) {}
isInputMethodConnectionActive()286 bool isInputMethodConnectionActive() override { return mFdp->ConsumeBool(); }
getPointerViewportForAssociatedDisplay(ui::LogicalDisplayId associatedDisplayId)287 std::optional<DisplayViewport> getPointerViewportForAssociatedDisplay(
288 ui::LogicalDisplayId associatedDisplayId) override {
289 return {};
290 }
291 };
292
293 class FuzzInputListener : public virtual InputListenerInterface {
294 public:
notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs & args)295 void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override {}
notifyConfigurationChanged(const NotifyConfigurationChangedArgs & args)296 void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override {}
notifyKey(const NotifyKeyArgs & args)297 void notifyKey(const NotifyKeyArgs& args) override {}
notifyMotion(const NotifyMotionArgs & args)298 void notifyMotion(const NotifyMotionArgs& args) override {}
notifySwitch(const NotifySwitchArgs & args)299 void notifySwitch(const NotifySwitchArgs& args) override {}
notifySensor(const NotifySensorArgs & args)300 void notifySensor(const NotifySensorArgs& args) override{};
notifyVibratorState(const NotifyVibratorStateArgs & args)301 void notifyVibratorState(const NotifyVibratorStateArgs& args) override{};
notifyDeviceReset(const NotifyDeviceResetArgs & args)302 void notifyDeviceReset(const NotifyDeviceResetArgs& args) override {}
notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs & args)303 void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override{};
304 };
305
306 class FuzzInputReaderContext : public InputReaderContext {
307 std::shared_ptr<EventHubInterface> mEventHub;
308 sp<InputReaderPolicyInterface> mPolicy;
309 std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp;
310
311 public:
FuzzInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp)312 FuzzInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
313 std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp)
314 : mEventHub(eventHub), mPolicy(sp<FuzzInputReaderPolicy>::make(fdp)), mFdp(fdp) {}
~FuzzInputReaderContext()315 ~FuzzInputReaderContext() {}
updateGlobalMetaState()316 void updateGlobalMetaState() override {}
getGlobalMetaState()317 int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); }
disableVirtualKeysUntil(nsecs_t time)318 void disableVirtualKeysUntil(nsecs_t time) override {}
shouldDropVirtualKey(nsecs_t now,int32_t keyCode,int32_t scanCode)319 bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override {
320 return mFdp->ConsumeBool();
321 }
requestTimeoutAtTime(nsecs_t when)322 void requestTimeoutAtTime(nsecs_t when) override {}
bumpGeneration()323 int32_t bumpGeneration() override { return mFdp->ConsumeIntegral<int32_t>(); }
getExternalStylusDevices(std::vector<InputDeviceInfo> & outDevices)324 void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override {}
dispatchExternalStylusState(const StylusState & outState)325 std::list<NotifyArgs> dispatchExternalStylusState(const StylusState& outState) override {
326 return {};
327 }
getPolicy()328 InputReaderPolicyInterface* getPolicy() override { return mPolicy.get(); }
getEventHub()329 EventHubInterface* getEventHub() override { return mEventHub.get(); }
getNextId()330 int32_t getNextId() override { return mFdp->ConsumeIntegral<int32_t>(); }
331
updateLedMetaState(int32_t metaState)332 void updateLedMetaState(int32_t metaState) override{};
getLedMetaState()333 int32_t getLedMetaState() override { return mFdp->ConsumeIntegral<int32_t>(); };
notifyStylusGestureStarted(int32_t,nsecs_t)334 void notifyStylusGestureStarted(int32_t, nsecs_t) {}
335
setPreventingTouchpadTaps(bool prevent)336 void setPreventingTouchpadTaps(bool prevent) {}
isPreventingTouchpadTaps()337 bool isPreventingTouchpadTaps() { return mFdp->ConsumeBool(); };
338
setLastKeyDownTimestamp(nsecs_t when)339 void setLastKeyDownTimestamp(nsecs_t when) { mLastKeyDownTimestamp = when; };
getLastKeyDownTimestamp()340 nsecs_t getLastKeyDownTimestamp() { return mLastKeyDownTimestamp; };
getKeyboardClassifier()341 KeyboardClassifier& getKeyboardClassifier() override { return *mClassifier; }
342
343 private:
344 nsecs_t mLastKeyDownTimestamp;
345 std::unique_ptr<KeyboardClassifier> mClassifier = std::make_unique<KeyboardClassifier>();
346 };
347
348 template <class Fdp>
getFuzzedInputDevice(Fdp & fdp,FuzzInputReaderContext * context)349 InputDevice getFuzzedInputDevice(Fdp& fdp, FuzzInputReaderContext* context) {
350 InputDeviceIdentifier identifier;
351 identifier.name = fdp.ConsumeRandomLengthString(16);
352 identifier.location = fdp.ConsumeRandomLengthString(12);
353 int32_t deviceID = fdp.ConsumeIntegralInRange(0, 5);
354 int32_t deviceGeneration = fdp.ConsumeIntegralInRange(0, 5);
355 return InputDevice(context, deviceID, deviceGeneration, identifier);
356 }
357
358 template <class Fdp>
configureAndResetDevice(Fdp & fdp,InputDevice & device)359 void configureAndResetDevice(Fdp& fdp, InputDevice& device) {
360 nsecs_t arbitraryTime = fdp.template ConsumeIntegral<nsecs_t>();
361 std::list<NotifyArgs> out;
362 out += device.configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{});
363 out += device.reset(arbitraryTime);
364 }
365
366 template <class Fdp, class T, typename... Args>
getMapperForDevice(Fdp & fdp,InputDevice & device,Args...args)367 T& getMapperForDevice(Fdp& fdp, InputDevice& device, Args... args) {
368 int32_t eventhubId = fdp.template ConsumeIntegral<int32_t>();
369 // ensure a device entry exists for this eventHubId
370 device.addEmptyEventHubDevice(eventhubId);
371 configureAndResetDevice(fdp, device);
372
373 return device.template constructAndAddMapper<T>(eventhubId, args...);
374 }
375
376 } // namespace android
377