1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=4 sw=4 sts=4 tw=80 et: */
3 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21 
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <hardware_legacy/power.h>
26 #include <signal.h>
27 #include <sys/epoll.h>
28 #include <sys/ioctl.h>
29 #include <sys/param.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <utils/BitSet.h>
34 
35 #include "base/basictypes.h"
36 #include "GonkPermission.h"
37 #include "libdisplay/BootAnimation.h"
38 #include "nscore.h"
39 #include "mozilla/TouchEvents.h"
40 #include "mozilla/FileUtils.h"
41 #include "mozilla/Hal.h"
42 #include "mozilla/MouseEvents.h"
43 #include "mozilla/Mutex.h"
44 #include "mozilla/Services.h"
45 #include "mozilla/TextEvents.h"
46 #if ANDROID_VERSION >= 18
47 #include "nativewindow/FakeSurfaceComposer.h"
48 #endif
49 #include "nsAppShell.h"
50 #include "mozilla/DebugOnly.h"
51 #include "mozilla/dom/Touch.h"
52 #include "nsGkAtoms.h"
53 #include "nsIObserverService.h"
54 #include "nsIScreen.h"
55 #include "nsScreenManagerGonk.h"
56 #include "nsThreadUtils.h"
57 #include "nsWindow.h"
58 #include "OrientationObserver.h"
59 #include "GonkMemoryPressureMonitoring.h"
60 
61 #include "android/log.h"
62 #include "libui/EventHub.h"
63 #include "libui/InputReader.h"
64 #include "libui/InputDispatcher.h"
65 
66 #include "mozilla/Preferences.h"
67 #include "GeckoProfiler.h"
68 
69 // Defines kKeyMapping and GetKeyNameIndex()
70 #include "GonkKeyMapping.h"
71 #include "mozilla/layers/CompositorBridgeParent.h"
72 #include "GeckoTouchDispatcher.h"
73 
74 #undef LOG
75 #define LOG(args...)                                            \
76     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
77 #ifdef VERBOSE_LOG_ENABLED
78 # define VERBOSE_LOG(args...)                           \
79     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
80 #else
81 # define VERBOSE_LOG(args...)                   \
82     (void)0
83 #endif
84 
85 using namespace android;
86 using namespace mozilla;
87 using namespace mozilla::dom;
88 using namespace mozilla::services;
89 using namespace mozilla::widget;
90 
91 bool gDrawRequest = false;
92 static nsAppShell *gAppShell = nullptr;
93 static int epollfd = 0;
94 static int signalfds[2] = {0};
95 static bool sDevInputAudioJack;
96 static int32_t sHeadphoneState;
97 static int32_t sMicrophoneState;
98 
99 // Amount of time in MS before an input is considered expired.
100 static const uint64_t kInputExpirationThresholdMs = 1000;
101 static const char kKey_WAKE_LOCK_ID[] = "GeckoKeyEvent";
102 
NS_IMPL_ISUPPORTS_INHERITED(nsAppShell,nsBaseAppShell,nsIObserver)103 NS_IMPL_ISUPPORTS_INHERITED(nsAppShell, nsBaseAppShell, nsIObserver)
104 
105 static uint64_t
106 nanosecsToMillisecs(nsecs_t nsecs)
107 {
108     return nsecs / 1000000;
109 }
110 
111 namespace mozilla {
112 
ProcessNextEvent()113 bool ProcessNextEvent()
114 {
115     return gAppShell->ProcessNextNativeEvent(true);
116 }
117 
NotifyEvent()118 void NotifyEvent()
119 {
120     gAppShell->NotifyNativeEvent();
121 }
122 
123 } // namespace mozilla
124 
125 static void
pipeHandler(int fd,FdHandler * data)126 pipeHandler(int fd, FdHandler *data)
127 {
128     ssize_t len;
129     do {
130         char tmp[32];
131         len = read(fd, tmp, sizeof(tmp));
132     } while (len > 0);
133 }
134 
135 struct Touch {
136     int32_t id;
137     PointerCoords coords;
138 };
139 
140 struct UserInputData {
141     uint64_t timeMs;
142     enum {
143         MOTION_DATA,
144         KEY_DATA
145     } type;
146     int32_t action;
147     int32_t flags;
148     int32_t metaState;
149     int32_t deviceId;
150     union {
151         struct {
152             int32_t keyCode;
153             int32_t scanCode;
154         } key;
155         struct {
156             int32_t touchCount;
157             ::Touch touches[MAX_POINTERS];
158         } motion;
159     };
160 };
161 
162 static mozilla::Modifiers
getDOMModifiers(int32_t metaState)163 getDOMModifiers(int32_t metaState)
164 {
165     mozilla::Modifiers result = 0;
166     if (metaState & (AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
167         result |= MODIFIER_ALT;
168     }
169     if (metaState & (AMETA_SHIFT_ON |
170                      AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
171         result |= MODIFIER_SHIFT;
172     }
173     if (metaState & AMETA_FUNCTION_ON) {
174         result |= MODIFIER_FN;
175     }
176     if (metaState & (AMETA_CTRL_ON |
177                      AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
178         result |= MODIFIER_CONTROL;
179     }
180     if (metaState & (AMETA_META_ON |
181                      AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
182         result |= MODIFIER_META;
183     }
184     if (metaState & AMETA_CAPS_LOCK_ON) {
185         result |= MODIFIER_CAPSLOCK;
186     }
187     if (metaState & AMETA_NUM_LOCK_ON) {
188         result |= MODIFIER_NUMLOCK;
189     }
190     if (metaState & AMETA_SCROLL_LOCK_ON) {
191         result |= MODIFIER_SCROLLLOCK;
192     }
193     return result;
194 }
195 
196 class MOZ_STACK_CLASS KeyEventDispatcher
197 {
198 public:
199     KeyEventDispatcher(const UserInputData& aData,
200                        KeyCharacterMap* aKeyCharMap);
201     void Dispatch();
202 
203 private:
204     const UserInputData& mData;
205     sp<KeyCharacterMap> mKeyCharMap;
206 
207     char16_t mChar;
208     char16_t mUnmodifiedChar;
209 
210     uint32_t mDOMKeyCode;
211     uint32_t mDOMKeyLocation;
212     KeyNameIndex mDOMKeyNameIndex;
213     CodeNameIndex mDOMCodeNameIndex;
214     char16_t mDOMPrintableKeyValue;
215 
IsKeyPress() const216     bool IsKeyPress() const
217     {
218         return mData.action == AKEY_EVENT_ACTION_DOWN;
219     }
IsRepeat() const220     bool IsRepeat() const
221     {
222         return IsKeyPress() && (mData.flags & AKEY_EVENT_FLAG_LONG_PRESS);
223     }
224 
225     char16_t PrintableKeyValue() const;
226 
UnmodifiedMetaState() const227     int32_t UnmodifiedMetaState() const
228     {
229         return mData.metaState &
230             ~(AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON |
231               AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON |
232               AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
233     }
234 
IsControlChar(char16_t aChar)235     static bool IsControlChar(char16_t aChar)
236     {
237         return (aChar < ' ' || aChar == 0x7F);
238     }
239 
240     void DispatchKeyDownEvent();
241     void DispatchKeyUpEvent();
242     nsEventStatus DispatchKeyEventInternal(EventMessage aEventMessage);
243 };
244 
KeyEventDispatcher(const UserInputData & aData,KeyCharacterMap * aKeyCharMap)245 KeyEventDispatcher::KeyEventDispatcher(const UserInputData& aData,
246                                        KeyCharacterMap* aKeyCharMap)
247     : mData(aData)
248     , mKeyCharMap(aKeyCharMap)
249     , mChar(0)
250     , mUnmodifiedChar(0)
251     , mDOMPrintableKeyValue(0)
252 {
253     // XXX Printable key's keyCode value should be computed with actual
254     //     input character.
255     mDOMKeyCode = (mData.key.keyCode < (ssize_t)ArrayLength(kKeyMapping)) ?
256         kKeyMapping[mData.key.keyCode] : 0;
257     mDOMKeyNameIndex = GetKeyNameIndex(mData.key.keyCode);
258     mDOMCodeNameIndex = GetCodeNameIndex(mData.key.scanCode);
259     mDOMKeyLocation =
260         WidgetKeyboardEvent::ComputeLocationFromCodeValue(mDOMCodeNameIndex);
261 
262     if (!mKeyCharMap.get()) {
263         return;
264     }
265 
266     mChar = mKeyCharMap->getCharacter(mData.key.keyCode, mData.metaState);
267     if (IsControlChar(mChar)) {
268         mChar = 0;
269     }
270     int32_t unmodifiedMetaState = UnmodifiedMetaState();
271     if (mData.metaState == unmodifiedMetaState) {
272         mUnmodifiedChar = mChar;
273     } else {
274         mUnmodifiedChar = mKeyCharMap->getCharacter(mData.key.keyCode,
275                                                     unmodifiedMetaState);
276         if (IsControlChar(mUnmodifiedChar)) {
277             mUnmodifiedChar = 0;
278         }
279     }
280 
281     mDOMPrintableKeyValue = PrintableKeyValue();
282 }
283 
284 char16_t
PrintableKeyValue() const285 KeyEventDispatcher::PrintableKeyValue() const
286 {
287     if (mDOMKeyNameIndex != KEY_NAME_INDEX_USE_STRING) {
288         return 0;
289     }
290     return mChar ? mChar : mUnmodifiedChar;
291 }
292 
293 nsEventStatus
DispatchKeyEventInternal(EventMessage aEventMessage)294 KeyEventDispatcher::DispatchKeyEventInternal(EventMessage aEventMessage)
295 {
296     WidgetKeyboardEvent event(true, aEventMessage, nullptr);
297     if (aEventMessage == eKeyPress) {
298         // XXX If the charCode is not a printable character, the charCode
299         //     should be computed without Ctrl/Alt/Meta modifiers.
300         event.mCharCode = static_cast<uint32_t>(mChar);
301     }
302     if (!event.mCharCode) {
303         event.mKeyCode = mDOMKeyCode;
304     }
305     event.mIsChar = !!event.mCharCode;
306     event.mIsRepeat = IsRepeat();
307     event.mKeyNameIndex = mDOMKeyNameIndex;
308     if (mDOMPrintableKeyValue) {
309         event.mKeyValue = mDOMPrintableKeyValue;
310     }
311     event.mCodeNameIndex = mDOMCodeNameIndex;
312     event.mModifiers = getDOMModifiers(mData.metaState);
313     event.mLocation = mDOMKeyLocation;
314     event.mTime = mData.timeMs;
315     return nsWindow::DispatchKeyInput(event);
316 }
317 
318 void
Dispatch()319 KeyEventDispatcher::Dispatch()
320 {
321     // XXX Even if unknown key is pressed, DOM key event should be
322     //     dispatched since Gecko for the other platforms are implemented
323     //     as so.
324     if (!mDOMKeyCode && mDOMKeyNameIndex == KEY_NAME_INDEX_Unidentified) {
325         VERBOSE_LOG("Got unknown key event code. "
326                     "type 0x%04x code 0x%04x value %d",
327                     mData.action, mData.key.keyCode, IsKeyPress());
328         return;
329     }
330 
331     if (IsKeyPress()) {
332         DispatchKeyDownEvent();
333     } else {
334         DispatchKeyUpEvent();
335     }
336 }
337 
338 void
DispatchKeyDownEvent()339 KeyEventDispatcher::DispatchKeyDownEvent()
340 {
341     nsEventStatus status = DispatchKeyEventInternal(eKeyDown);
342     if (status != nsEventStatus_eConsumeNoDefault) {
343         DispatchKeyEventInternal(eKeyPress);
344     }
345 }
346 
347 void
DispatchKeyUpEvent()348 KeyEventDispatcher::DispatchKeyUpEvent()
349 {
350     DispatchKeyEventInternal(eKeyUp);
351 }
352 
353 class SwitchEventRunnable : public mozilla::Runnable {
354 public:
SwitchEventRunnable(hal::SwitchEvent & aEvent)355     SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent)
356     {}
357 
Run()358     NS_IMETHOD Run() override
359     {
360         hal::NotifySwitchStateFromInputDevice(mEvent.device(),
361           mEvent.status());
362         return NS_OK;
363     }
364 private:
365     hal::SwitchEvent mEvent;
366 };
367 
368 static void
updateHeadphoneSwitch()369 updateHeadphoneSwitch()
370 {
371     hal::SwitchEvent event;
372 
373     switch (sHeadphoneState) {
374     case AKEY_STATE_UP:
375         event.status() = hal::SWITCH_STATE_OFF;
376         break;
377     case AKEY_STATE_DOWN:
378         event.status() = sMicrophoneState == AKEY_STATE_DOWN ?
379             hal::SWITCH_STATE_HEADSET : hal::SWITCH_STATE_HEADPHONE;
380         break;
381     default:
382         return;
383     }
384 
385     event.device() = hal::SWITCH_HEADPHONES;
386     NS_DispatchToMainThread(new SwitchEventRunnable(event));
387 }
388 
389 class GeckoPointerController : public PointerControllerInterface {
390     float mX;
391     float mY;
392     int32_t mButtonState;
393     InputReaderConfiguration* mConfig;
394 public:
GeckoPointerController(InputReaderConfiguration * config)395     GeckoPointerController(InputReaderConfiguration* config)
396         : mX(0)
397         , mY(0)
398         , mButtonState(0)
399         , mConfig(config)
400     {}
401 
402     virtual bool getBounds(float* outMinX, float* outMinY,
403             float* outMaxX, float* outMaxY) const;
404     virtual void move(float deltaX, float deltaY);
405     virtual void setButtonState(int32_t buttonState);
406     virtual int32_t getButtonState() const;
407     virtual void setPosition(float x, float y);
408     virtual void getPosition(float* outX, float* outY) const;
fade(Transition transition)409     virtual void fade(Transition transition) {}
unfade(Transition transition)410     virtual void unfade(Transition transition) {}
setPresentation(Presentation presentation)411     virtual void setPresentation(Presentation presentation) {}
setSpots(const PointerCoords * spotCoords,const uint32_t * spotIdToIndex,BitSet32 spotIdBits)412     virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
413             BitSet32 spotIdBits) {}
clearSpots()414     virtual void clearSpots() {}
415 };
416 
417 bool
getBounds(float * outMinX,float * outMinY,float * outMaxX,float * outMaxY) const418 GeckoPointerController::getBounds(float* outMinX,
419                                   float* outMinY,
420                                   float* outMaxX,
421                                   float* outMaxY) const
422 {
423     DisplayViewport viewport;
424 
425     mConfig->getDisplayInfo(false, &viewport);
426 
427     *outMinX = *outMinY = 0;
428     *outMaxX = viewport.logicalRight;
429     *outMaxY = viewport.logicalBottom;
430     return true;
431 }
432 
433 void
move(float deltaX,float deltaY)434 GeckoPointerController::move(float deltaX, float deltaY)
435 {
436     float minX, minY, maxX, maxY;
437     getBounds(&minX, &minY, &maxX, &maxY);
438 
439     mX = clamped(mX + deltaX, minX, maxX);
440     mY = clamped(mY + deltaY, minY, maxY);
441 }
442 
443 void
setButtonState(int32_t buttonState)444 GeckoPointerController::setButtonState(int32_t buttonState)
445 {
446     mButtonState = buttonState;
447 }
448 
449 int32_t
getButtonState() const450 GeckoPointerController::getButtonState() const
451 {
452     return mButtonState;
453 }
454 
455 void
setPosition(float x,float y)456 GeckoPointerController::setPosition(float x, float y)
457 {
458     mX = x;
459     mY = y;
460 }
461 
462 void
getPosition(float * outX,float * outY) const463 GeckoPointerController::getPosition(float* outX, float* outY) const
464 {
465     *outX = mX;
466     *outY = mY;
467 }
468 
469 class GeckoInputReaderPolicy : public InputReaderPolicyInterface {
470     InputReaderConfiguration mConfig;
471 public:
GeckoInputReaderPolicy()472     GeckoInputReaderPolicy() {}
473 
474     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
obtainPointerController(int32_t deviceId)475     virtual sp<PointerControllerInterface> obtainPointerController(int32_t
476 deviceId)
477     {
478         return new GeckoPointerController(&mConfig);
479     };
notifyInputDevicesChanged(const android::Vector<InputDeviceInfo> & inputDevices)480     virtual void notifyInputDevicesChanged(const android::Vector<InputDeviceInfo>& inputDevices) {};
getKeyboardLayoutOverlay(const String8 & inputDeviceDescriptor)481     virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor)
482     {
483         return nullptr;
484     };
getDeviceAlias(const InputDeviceIdentifier & identifier)485     virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier)
486     {
487         return String8::empty();
488     };
489 
490     void setDisplayInfo();
491 
492 protected:
~GeckoInputReaderPolicy()493     virtual ~GeckoInputReaderPolicy() {}
494 };
495 
496 class GeckoInputDispatcher : public InputDispatcherInterface {
497 public:
GeckoInputDispatcher(sp<EventHub> & aEventHub)498     GeckoInputDispatcher(sp<EventHub> &aEventHub)
499         : mQueueLock("GeckoInputDispatcher::mQueueMutex")
500         , mEventHub(aEventHub)
501         , mKeyDownCount(0)
502         , mKeyEventsFiltered(false)
503         , mPowerWakelock(false)
504     {
505         mTouchDispatcher = GeckoTouchDispatcher::GetInstance();
506     }
507 
508     virtual void dump(String8& dump);
509 
monitor()510     virtual void monitor() {}
511 
512     // Called on the main thread
513     virtual void dispatchOnce();
514 
515     // notify* methods are called on the InputReaderThread
516     virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
517     virtual void notifyKey(const NotifyKeyArgs* args);
518     virtual void notifyMotion(const NotifyMotionArgs* args);
519     virtual void notifySwitch(const NotifySwitchArgs* args);
520     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
521 
522     virtual int32_t injectInputEvent(const InputEvent* event,
523             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
524             uint32_t policyFlags);
525 
526     virtual void setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles);
527     virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
528 
529     virtual void setInputDispatchMode(bool enabled, bool frozen);
setInputFilterEnabled(bool enabled)530     virtual void setInputFilterEnabled(bool enabled) {}
transferTouchFocus(const sp<InputChannel> & fromChannel,const sp<InputChannel> & toChannel)531     virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel,
532             const sp<InputChannel>& toChannel) { return true; }
533 
534     virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
535             const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
536     virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
537 
538 
539 
540 protected:
~GeckoInputDispatcher()541     virtual ~GeckoInputDispatcher() { }
542 
543 private:
544     // mQueueLock should generally be locked while using mEventQueue.
545     // UserInputData is pushed on on the InputReaderThread and
546     // popped and dispatched on the main thread.
547     mozilla::Mutex mQueueLock;
548     std::queue<UserInputData> mEventQueue;
549     sp<EventHub> mEventHub;
550     RefPtr<GeckoTouchDispatcher> mTouchDispatcher;
551 
552     int mKeyDownCount;
553     bool mKeyEventsFiltered;
554     bool mPowerWakelock;
555 };
556 
557 // GeckoInputReaderPolicy
558 void
setDisplayInfo()559 GeckoInputReaderPolicy::setDisplayInfo()
560 {
561     static_assert(static_cast<int>(nsIScreen::ROTATION_0_DEG) ==
562                   static_cast<int>(DISPLAY_ORIENTATION_0),
563                   "Orientation enums not matched!");
564     static_assert(static_cast<int>(nsIScreen::ROTATION_90_DEG) ==
565                   static_cast<int>(DISPLAY_ORIENTATION_90),
566                   "Orientation enums not matched!");
567     static_assert(static_cast<int>(nsIScreen::ROTATION_180_DEG) ==
568                   static_cast<int>(DISPLAY_ORIENTATION_180),
569                   "Orientation enums not matched!");
570     static_assert(static_cast<int>(nsIScreen::ROTATION_270_DEG) ==
571                   static_cast<int>(DISPLAY_ORIENTATION_270),
572                   "Orientation enums not matched!");
573 
574     RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen();
575 
576     uint32_t rotation = nsIScreen::ROTATION_0_DEG;
577     DebugOnly<nsresult> rv = screen->GetRotation(&rotation);
578     MOZ_ASSERT(NS_SUCCEEDED(rv));
579     LayoutDeviceIntRect screenBounds = screen->GetNaturalBounds();
580 
581     DisplayViewport viewport;
582     viewport.displayId = 0;
583     viewport.orientation = rotation;
584     viewport.physicalRight = viewport.deviceWidth = screenBounds.width;
585     viewport.physicalBottom = viewport.deviceHeight = screenBounds.height;
586     if (viewport.orientation == DISPLAY_ORIENTATION_90 ||
587         viewport.orientation == DISPLAY_ORIENTATION_270) {
588         viewport.logicalRight = screenBounds.height;
589         viewport.logicalBottom = screenBounds.width;
590     } else {
591         viewport.logicalRight = screenBounds.width;
592         viewport.logicalBottom = screenBounds.height;
593     }
594     mConfig.setDisplayInfo(false, viewport);
595 }
596 
getReaderConfiguration(InputReaderConfiguration * outConfig)597 void GeckoInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig)
598 {
599     *outConfig = mConfig;
600 }
601 
602 
603 // GeckoInputDispatcher
604 void
dump(String8 & dump)605 GeckoInputDispatcher::dump(String8& dump)
606 {
607 }
608 
609 static bool
isExpired(const UserInputData & data)610 isExpired(const UserInputData& data)
611 {
612     uint64_t timeNowMs =
613         nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC));
614     return (timeNowMs - data.timeMs) > kInputExpirationThresholdMs;
615 }
616 
617 void
dispatchOnce()618 GeckoInputDispatcher::dispatchOnce()
619 {
620     UserInputData data;
621     {
622         MutexAutoLock lock(mQueueLock);
623         if (mEventQueue.empty())
624             return;
625         data = mEventQueue.front();
626         mEventQueue.pop();
627         if (!mEventQueue.empty())
628             gAppShell->NotifyNativeEvent();
629     }
630 
631     switch (data.type) {
632     case UserInputData::MOTION_DATA: {
633         MOZ_ASSERT_UNREACHABLE("Should not dispatch touch events here anymore");
634         break;
635     }
636     case UserInputData::KEY_DATA: {
637         if (!mKeyDownCount) {
638             // No pending events, the filter state can be updated.
639             mKeyEventsFiltered = isExpired(data);
640         }
641 
642         mKeyDownCount += (data.action == AKEY_EVENT_ACTION_DOWN) ? 1 : -1;
643         if (mKeyEventsFiltered) {
644             return;
645         }
646 
647         sp<KeyCharacterMap> kcm = mEventHub->getKeyCharacterMap(data.deviceId);
648         KeyEventDispatcher dispatcher(data, kcm.get());
649         dispatcher.Dispatch();
650         break;
651     }
652     }
653     MutexAutoLock lock(mQueueLock);
654     if (mPowerWakelock && mEventQueue.empty()) {
655         release_wake_lock(kKey_WAKE_LOCK_ID);
656         mPowerWakelock = false;
657     }
658 }
659 
660 void
notifyConfigurationChanged(const NotifyConfigurationChangedArgs *)661 GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs*)
662 {
663     gAppShell->CheckPowerKey();
664 }
665 
666 void
notifyKey(const NotifyKeyArgs * args)667 GeckoInputDispatcher::notifyKey(const NotifyKeyArgs* args)
668 {
669     UserInputData data;
670     data.timeMs = nanosecsToMillisecs(args->eventTime);
671     data.type = UserInputData::KEY_DATA;
672     data.action = args->action;
673     data.flags = args->flags;
674     data.metaState = args->metaState;
675     data.deviceId = args->deviceId;
676     data.key.keyCode = args->keyCode;
677     data.key.scanCode = args->scanCode;
678     {
679         MutexAutoLock lock(mQueueLock);
680         mEventQueue.push(data);
681         if (!mPowerWakelock) {
682             mPowerWakelock =
683                 acquire_wake_lock(PARTIAL_WAKE_LOCK, kKey_WAKE_LOCK_ID);
684         }
685     }
686     gAppShell->NotifyNativeEvent();
687 }
688 
689 static void
addMultiTouch(MultiTouchInput & aMultiTouch,const NotifyMotionArgs * args,int aIndex)690 addMultiTouch(MultiTouchInput& aMultiTouch,
691                                     const NotifyMotionArgs* args, int aIndex)
692 {
693     int32_t id = args->pointerProperties[aIndex].id;
694     PointerCoords coords = args->pointerCoords[aIndex];
695     float force = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE);
696 
697     float orientation = coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
698     float rotationAngle = orientation * 180 / M_PI;
699     if (rotationAngle == 90) {
700       rotationAngle = -90;
701     }
702 
703     float radiusX, radiusY;
704     if (rotationAngle < 0) {
705       radiusX = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR) / 2;
706       radiusY = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR) / 2;
707       rotationAngle += 90;
708     } else {
709       radiusX = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR) / 2;
710       radiusY = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR) / 2;
711     }
712 
713     ScreenIntPoint point = ScreenIntPoint::Round(coords.getX(),
714                                                  coords.getY());
715 
716     SingleTouchData touchData(id, point, ScreenSize(radiusX, radiusY),
717                               rotationAngle, force);
718 
719     aMultiTouch.mTouches.AppendElement(touchData);
720 }
721 
722 void
notifyMotion(const NotifyMotionArgs * args)723 GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args)
724 {
725     uint32_t time = nanosecsToMillisecs(args->eventTime);
726     int32_t action = args->action & AMOTION_EVENT_ACTION_MASK;
727     int touchCount = args->pointerCount;
728     MOZ_ASSERT(touchCount <= MAX_POINTERS);
729     TimeStamp timestamp = mozilla::TimeStamp::FromSystemTime(args->eventTime);
730     Modifiers modifiers = getDOMModifiers(args->metaState);
731 
732     MultiTouchInput::MultiTouchType touchType = MultiTouchInput::MULTITOUCH_CANCEL;
733     switch (action) {
734     case AMOTION_EVENT_ACTION_DOWN:
735     case AMOTION_EVENT_ACTION_POINTER_DOWN:
736         touchType = MultiTouchInput::MULTITOUCH_START;
737         break;
738     case AMOTION_EVENT_ACTION_MOVE:
739         touchType = MultiTouchInput::MULTITOUCH_MOVE;
740         break;
741     case AMOTION_EVENT_ACTION_UP:
742     case AMOTION_EVENT_ACTION_POINTER_UP:
743         touchType = MultiTouchInput::MULTITOUCH_END;
744         break;
745     case AMOTION_EVENT_ACTION_OUTSIDE:
746     case AMOTION_EVENT_ACTION_CANCEL:
747         touchType = MultiTouchInput::MULTITOUCH_CANCEL;
748         break;
749     case AMOTION_EVENT_ACTION_HOVER_EXIT:
750     case AMOTION_EVENT_ACTION_HOVER_ENTER:
751     case AMOTION_EVENT_ACTION_HOVER_MOVE:
752         NS_WARNING("Ignoring hover touch events");
753         return;
754     default:
755         MOZ_ASSERT_UNREACHABLE("Could not assign a touch type");
756         break;
757     }
758 
759     MultiTouchInput touchData(touchType, time, timestamp, modifiers);
760 
761     // For touch ends, we have to filter out which finger is actually
762     // the touch end since the touch array has all fingers, not just the touch
763     // that we want to end
764     if (touchType == MultiTouchInput::MULTITOUCH_END) {
765         int touchIndex = args->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK;
766         touchIndex >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
767         addMultiTouch(touchData, args, touchIndex);
768     } else {
769         for (int32_t i = 0; i < touchCount; ++i) {
770             addMultiTouch(touchData, args, i);
771         }
772     }
773 
774     mTouchDispatcher->NotifyTouch(touchData, timestamp);
775 }
776 
notifySwitch(const NotifySwitchArgs * args)777 void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args)
778 {
779     if (!sDevInputAudioJack)
780         return;
781 
782     bool needSwitchUpdate = false;
783 
784     if (args->switchMask & (1 << SW_HEADPHONE_INSERT)) {
785         sHeadphoneState = (args->switchValues & (1 << SW_HEADPHONE_INSERT)) ?
786                           AKEY_STATE_DOWN : AKEY_STATE_UP;
787         needSwitchUpdate = true;
788     }
789 
790     if (args->switchMask & (1 << SW_MICROPHONE_INSERT)) {
791         sMicrophoneState = (args->switchValues & (1 << SW_MICROPHONE_INSERT)) ?
792                            AKEY_STATE_DOWN : AKEY_STATE_UP;
793         needSwitchUpdate = true;
794     }
795 
796     if (needSwitchUpdate)
797         updateHeadphoneSwitch();
798 }
799 
notifyDeviceReset(const NotifyDeviceResetArgs * args)800 void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args)
801 {
802 }
803 
injectInputEvent(const InputEvent * event,int32_t injectorPid,int32_t injectorUid,int32_t syncMode,int32_t timeoutMillis,uint32_t policyFlags)804 int32_t GeckoInputDispatcher::injectInputEvent(
805     const InputEvent* event,
806     int32_t injectorPid, int32_t injectorUid, int32_t syncMode,
807     int32_t timeoutMillis, uint32_t policyFlags)
808 {
809     return INPUT_EVENT_INJECTION_SUCCEEDED;
810 }
811 
812 void
setInputWindows(const android::Vector<sp<InputWindowHandle>> & inputWindowHandles)813 GeckoInputDispatcher::setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles)
814 {
815 }
816 
817 void
setFocusedApplication(const sp<InputApplicationHandle> & inputApplicationHandle)818 GeckoInputDispatcher::setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle)
819 {
820 }
821 
822 void
setInputDispatchMode(bool enabled,bool frozen)823 GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen)
824 {
825 }
826 
827 status_t
registerInputChannel(const sp<InputChannel> & inputChannel,const sp<InputWindowHandle> & inputWindowHandle,bool monitor)828 GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
829                                            const sp<InputWindowHandle>& inputWindowHandle, bool monitor)
830 {
831     return OK;
832 }
833 
834 status_t
unregisterInputChannel(const sp<InputChannel> & inputChannel)835 GeckoInputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel)
836 {
837     return OK;
838 }
839 
nsAppShell()840 nsAppShell::nsAppShell()
841     : mNativeCallbackRequest(false)
842     , mEnableDraw(false)
843     , mHandlers()
844     , mPowerKeyChecked(false)
845 {
846     gAppShell = this;
847     if (XRE_IsParentProcess()) {
848         Preferences::SetCString("b2g.safe_mode", "unset");
849     }
850 }
851 
~nsAppShell()852 nsAppShell::~nsAppShell()
853 {
854     // mReaderThread and mEventHub will both be null if InitInputDevices
855     // is not called.
856     if (mReaderThread.get()) {
857         // We separate requestExit() and join() here so we can wake the EventHub's
858         // input loop, and stop it from polling for input events
859         mReaderThread->requestExit();
860         mEventHub->wake();
861 
862         status_t result = mReaderThread->requestExitAndWait();
863         if (result)
864             LOG("Could not stop reader thread - %d", result);
865     }
866     gAppShell = nullptr;
867 }
868 
869 nsresult
Init()870 nsAppShell::Init()
871 {
872     nsresult rv = nsBaseAppShell::Init();
873     NS_ENSURE_SUCCESS(rv, rv);
874 
875     epollfd = epoll_create(16);
876     NS_ENSURE_TRUE(epollfd >= 0, NS_ERROR_UNEXPECTED);
877 
878     int ret = pipe2(signalfds, O_NONBLOCK);
879     NS_ENSURE_FALSE(ret, NS_ERROR_UNEXPECTED);
880 
881     rv = AddFdHandler(signalfds[0], pipeHandler, "");
882     NS_ENSURE_SUCCESS(rv, rv);
883 
884     InitGonkMemoryPressureMonitoring();
885 
886     if (XRE_IsParentProcess()) {
887         printf("*****************************************************************\n");
888         printf("***\n");
889         printf("*** This is stdout. Most of the useful output will be in logcat.\n");
890         printf("***\n");
891         printf("*****************************************************************\n");
892         GonkPermissionService::instantiate();
893 
894         // Causes the kernel timezone to be set, which in turn causes the
895         // timestamps on SD cards to have the local time rather than UTC time.
896         hal::SetTimezone(hal::GetTimezone());
897     }
898 
899     nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
900     if (obsServ) {
901         obsServ->AddObserver(this, "browser-ui-startup-complete", false);
902         obsServ->AddObserver(this, "network-connection-state-changed", false);
903     }
904 
905     // Delay initializing input devices until the screen has been
906     // initialized (and we know the resolution).
907     return rv;
908 }
909 
910 void
CheckPowerKey()911 nsAppShell::CheckPowerKey()
912 {
913     if (mPowerKeyChecked) {
914         return;
915     }
916 
917     uint32_t deviceId = 0;
918     int32_t powerState = AKEY_STATE_UNKNOWN;
919 
920     // EventHub doesn't report the number of devices.
921     while (powerState != AKEY_STATE_DOWN && deviceId < 32) {
922         powerState = mEventHub->getKeyCodeState(deviceId++, AKEYCODE_POWER);
923     }
924 
925     // If Power is pressed while we startup, mark safe mode.
926     // Consumers of the b2g.safe_mode preference need to listen on this
927     // preference change to prevent startup races.
928     nsCOMPtr<nsIRunnable> prefSetter =
929     NS_NewRunnableFunction([powerState] () -> void {
930         Preferences::SetCString("b2g.safe_mode",
931                                 (powerState == AKEY_STATE_DOWN) ? "yes" : "no");
932     });
933     NS_DispatchToMainThread(prefSetter.forget());
934 
935     mPowerKeyChecked = true;
936 }
937 
938 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)939 nsAppShell::Observe(nsISupports* aSubject,
940                     const char* aTopic,
941                     const char16_t* aData)
942 {
943     if (!strcmp(aTopic, "network-connection-state-changed")) {
944         NS_ConvertUTF16toUTF8 type(aData);
945         if (!type.IsEmpty()) {
946             hal::NotifyNetworkChange(hal::NetworkInformation(atoi(type.get()), 0, 0));
947         }
948         return NS_OK;
949     } else if (!strcmp(aTopic, "browser-ui-startup-complete")) {
950         if (sDevInputAudioJack) {
951             sHeadphoneState  = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_HEADPHONE_INSERT);
952             sMicrophoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_MICROPHONE_INSERT);
953             updateHeadphoneSwitch();
954         }
955         mEnableDraw = true;
956 
957         // System is almost booting up. Stop the bootAnim now.
958         StopBootAnimation();
959 
960         NotifyEvent();
961         return NS_OK;
962     }
963 
964     return nsBaseAppShell::Observe(aSubject, aTopic, aData);
965 }
966 
967 NS_IMETHODIMP
Exit()968 nsAppShell::Exit()
969 {
970     OrientationObserver::ShutDown();
971     nsCOMPtr<nsIObserverService> obsServ = GetObserverService();
972     if (obsServ) {
973         obsServ->RemoveObserver(this, "browser-ui-startup-complete");
974         obsServ->RemoveObserver(this, "network-connection-state-changed");
975     }
976     return nsBaseAppShell::Exit();
977 }
978 
979 void
InitInputDevices()980 nsAppShell::InitInputDevices()
981 {
982     sDevInputAudioJack = hal::IsHeadphoneEventFromInputDev();
983     sHeadphoneState = AKEY_STATE_UNKNOWN;
984     sMicrophoneState = AKEY_STATE_UNKNOWN;
985 
986     mEventHub = new EventHub();
987     mReaderPolicy = new GeckoInputReaderPolicy();
988     mReaderPolicy->setDisplayInfo();
989     mDispatcher = new GeckoInputDispatcher(mEventHub);
990 
991     mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher);
992     mReaderThread = new InputReaderThread(mReader);
993 
994     status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
995     if (result) {
996         LOG("Failed to initialize InputReader thread, bad things are going to happen...");
997     }
998 }
999 
1000 nsresult
AddFdHandler(int fd,FdHandlerCallback handlerFunc,const char * deviceName)1001 nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc,
1002                          const char* deviceName)
1003 {
1004     epoll_event event = {
1005         EPOLLIN,
1006         { 0 }
1007     };
1008 
1009     FdHandler *handler = mHandlers.AppendElement();
1010     handler->fd = fd;
1011     strncpy(handler->name, deviceName, sizeof(handler->name) - 1);
1012     handler->func = handlerFunc;
1013     event.data.u32 = mHandlers.Length() - 1;
1014     return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) ?
1015            NS_ERROR_UNEXPECTED : NS_OK;
1016 }
1017 
1018 void
ScheduleNativeEventCallback()1019 nsAppShell::ScheduleNativeEventCallback()
1020 {
1021     mNativeCallbackRequest = true;
1022     NotifyEvent();
1023 }
1024 
1025 bool
ProcessNextNativeEvent(bool mayWait)1026 nsAppShell::ProcessNextNativeEvent(bool mayWait)
1027 {
1028     PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent",
1029         js::ProfileEntry::Category::EVENTS);
1030 
1031     epoll_event events[16] = {{ 0 }};
1032 
1033     int event_count;
1034     {
1035         PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait",
1036             js::ProfileEntry::Category::EVENTS);
1037 
1038         if ((event_count = epoll_wait(epollfd, events, 16,  mayWait ? -1 : 0)) <= 0)
1039             return true;
1040     }
1041 
1042     for (int i = 0; i < event_count; i++)
1043         mHandlers[events[i].data.u32].run();
1044 
1045     if (mDispatcher.get())
1046         mDispatcher->dispatchOnce();
1047 
1048     // NativeEventCallback always schedules more if it needs it
1049     // so we can coalesce these.
1050     // See the implementation in nsBaseAppShell.cpp for more info
1051     if (mNativeCallbackRequest) {
1052         mNativeCallbackRequest = false;
1053         NativeEventCallback();
1054     }
1055 
1056     if (gDrawRequest && mEnableDraw) {
1057         gDrawRequest = false;
1058         nsWindow::DoDraw();
1059     }
1060 
1061     return true;
1062 }
1063 
1064 void
NotifyNativeEvent()1065 nsAppShell::NotifyNativeEvent()
1066 {
1067     write(signalfds[1], "w", 1);
1068 }
1069 
1070 /* static */ void
NotifyScreenInitialized()1071 nsAppShell::NotifyScreenInitialized()
1072 {
1073     gAppShell->InitInputDevices();
1074 
1075     // Getting the instance of OrientationObserver to initialize it.
1076     OrientationObserver::GetInstance();
1077 }
1078 
1079 /* static */ void
NotifyScreenRotation()1080 nsAppShell::NotifyScreenRotation()
1081 {
1082     gAppShell->mReaderPolicy->setDisplayInfo();
1083     gAppShell->mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
1084 
1085     RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen();
1086     hal::NotifyScreenConfigurationChange(screen->GetConfiguration());
1087 }
1088