Bug 1221730 - Postpone singleton release in GamepadPlatformService::MaybeShutdown. r=baku
authorChih-Yi Leu <cleu@mozilla.com>
Tue, 28 Jun 2016 00:27:00 +0200
changeset 302842 8f8875dbdc71478aaf172c2a5c146443f171496d
parent 302841 050df9c81c1e80c03e75905716ec95343d83bf0f
child 302843 c79d6cf318c472b95996577b827d28c8bff61a34
push id30376
push usercbook@mozilla.com
push dateTue, 28 Jun 2016 14:09:36 +0000
treeherdermozilla-central@e45890951ce7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1221730
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1221730 - Postpone singleton release in GamepadPlatformService::MaybeShutdown. r=baku
dom/gamepad/GamepadMonitoring.cpp
dom/gamepad/GamepadPlatformService.cpp
dom/gamepad/GamepadPlatformService.h
dom/gamepad/cocoa/CocoaGamepad.cpp
dom/gamepad/ipc/GamepadEventChannelParent.cpp
dom/gamepad/ipc/GamepadTestChannelParent.cpp
dom/gamepad/linux/LinuxGamepad.cpp
dom/gamepad/windows/WindowsGamepad.cpp
widget/android/nsAppShell.cpp
--- a/dom/gamepad/GamepadMonitoring.cpp
+++ b/dom/gamepad/GamepadMonitoring.cpp
@@ -12,17 +12,17 @@ using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
 void
 MaybeStopGamepadMonitoring()
 {
   AssertIsOnBackgroundThread();
-  GamepadPlatformService* service =
+  RefPtr<GamepadPlatformService> service =
     GamepadPlatformService::GetParentService();
   MOZ_ASSERT(service);
   if(service->HasGamepadListeners()) {
     return;
   }
   StopGamepadMonitoring();
   service->ResetGamepadIndexes();
   service->MaybeShutdown();
--- a/dom/gamepad/GamepadPlatformService.cpp
+++ b/dom/gamepad/GamepadPlatformService.cpp
@@ -19,40 +19,46 @@ using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 // This is the singleton instance of GamepadPlatformService, can be called
 // by both background and monitor thread.
-StaticAutoPtr<GamepadPlatformService> gGamepadPlatformServiceSingleton;
+StaticRefPtr<GamepadPlatformService> gGamepadPlatformServiceSingleton;
 
 } //namepsace
 
 GamepadPlatformService::GamepadPlatformService()
   : mGamepadIndex(0),
     mMutex("mozilla::dom::GamepadPlatformService")
 {}
 
 GamepadPlatformService::~GamepadPlatformService()
 {
   Cleanup();
 }
 
 // static
-GamepadPlatformService*
+already_AddRefed<GamepadPlatformService>
 GamepadPlatformService::GetParentService()
 {
   //GamepadPlatformService can only be accessed in parent process
   MOZ_ASSERT(XRE_IsParentProcess());
-  if(!gGamepadPlatformServiceSingleton) {
-    gGamepadPlatformServiceSingleton = new GamepadPlatformService();
+  if (!gGamepadPlatformServiceSingleton) {
+    // Only Background Thread can create new GamepadPlatformService instance.
+    if (IsOnBackgroundThread()) {
+      gGamepadPlatformServiceSingleton = new GamepadPlatformService();
+    } else {
+      return nullptr;
+    }
   }
-  return gGamepadPlatformServiceSingleton;
+  RefPtr<GamepadPlatformService> service(gGamepadPlatformServiceSingleton);
+  return service.forget();
 }
 
 template<class T>
 void
 GamepadPlatformService::NotifyGamepadChange(const T& aInfo)
 {
   // This method is called by monitor populated in
   // platform-dependent backends
@@ -190,23 +196,31 @@ GamepadPlatformService::HasGamepadListen
 
 void
 GamepadPlatformService::MaybeShutdown()
 {
   // This method is invoked in MaybeStopGamepadMonitoring when
   // an IPDL channel is going to be destroyed
   AssertIsOnBackgroundThread();
 
+  // We have to release gGamepadPlatformServiceSingleton ouside
+  // the mutex as well as making upcoming GetParentService() call
+  // recreate new singleton, so we use this RefPtr to temporarily
+  // hold the reference, postponing the release process until this
+  // method ends.
+  RefPtr<GamepadPlatformService> kungFuDeathGrip;
+
   bool isChannelParentEmpty;
   {
     MutexAutoLock autoLock(mMutex);
     isChannelParentEmpty = mChannelParents.IsEmpty();
-  }
-  if(isChannelParentEmpty) {
-    gGamepadPlatformServiceSingleton = nullptr;
+    if(isChannelParentEmpty) {
+      kungFuDeathGrip = gGamepadPlatformServiceSingleton;
+      gGamepadPlatformServiceSingleton = nullptr;
+    }
   }
 }
 
 void
 GamepadPlatformService::Cleanup()
 {
   // This method is called when GamepadPlatformService is
   // successfully distructed in background thread
--- a/dom/gamepad/GamepadPlatformService.h
+++ b/dom/gamepad/GamepadPlatformService.h
@@ -26,20 +26,20 @@ class GamepadEventChannelParent;
 //    This thread takes charge of IPDL communications
 //    between here and DOM side
 //
 // 2. Monitor Thread:
 //    This thread is populated in platform-dependent backends, which
 //    is in charge of processing gamepad hardware events from OS
 class GamepadPlatformService final
 {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GamepadPlatformService)
  public:
-  ~GamepadPlatformService();
   //Get the singleton service
-  static GamepadPlatformService* GetParentService();
+  static already_AddRefed<GamepadPlatformService> GetParentService();
 
   // Add a gamepad to the list of known gamepads, and return its index.
   uint32_t AddGamepad(const char* aID, GamepadMappingType aMapping,
                       uint32_t aNumButtons, uint32_t aNumAxes);
   // Remove the gamepad at |aIndex| from the list of known gamepads.
   void RemoveGamepad(uint32_t aIndex);
 
   // Update the state of |aButton| for the gamepad at |aIndex| for all
@@ -67,16 +67,17 @@ class GamepadPlatformService final
   void RemoveChannelParent(GamepadEventChannelParent* aParent);
 
   bool HasGamepadListeners();
 
   void MaybeShutdown();
 
  private:
   GamepadPlatformService();
+  ~GamepadPlatformService();
   template<class T> void NotifyGamepadChange(const T& aInfo);
   void Cleanup();
 
   // mGamepadIndex can only be accessed by monitor thread
   uint32_t mGamepadIndex;
 
   // mChannelParents stores all the GamepadEventChannelParent instances
   // which may be accessed by both background thread and monitor thread
--- a/dom/gamepad/cocoa/CocoaGamepad.cpp
+++ b/dom/gamepad/cocoa/CocoaGamepad.cpp
@@ -242,16 +242,22 @@ class DarwinGamepadServiceStartupRunnabl
     mService->StartupInternal();
     return NS_OK;
   }
 };
 
 void
 DarwinGamepadService::DeviceAdded(IOHIDDeviceRef device)
 {
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return;
+  }
+
   size_t slot = size_t(-1);
   for (size_t i = 0; i < mGamepads.size(); i++) {
     if (mGamepads[i] == device)
       return;
     if (slot == size_t(-1) && mGamepads[i].empty())
       slot = i;
   }
 
@@ -271,32 +277,31 @@ DarwinGamepadService::DeviceAdded(IOHIDD
   int vendorId, productId;
   CFNumberGetValue(vendorIdRef, kCFNumberIntType, &vendorId);
   CFNumberGetValue(productIdRef, kCFNumberIntType, &productId);
   char product_name[128];
   CFStringGetCString(productRef, product_name,
                      sizeof(product_name), kCFStringEncodingASCII);
   char buffer[256];
   sprintf(buffer, "%x-%x-%s", vendorId, productId, product_name);
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
   uint32_t index = service->AddGamepad(buffer,
                                        mozilla::dom::GamepadMappingType::_empty,
                                        (int)mGamepads[slot].numButtons(),
                                        (int)mGamepads[slot].numAxes());
   mGamepads[slot].mSuperIndex = index;
 }
 
 void
 DarwinGamepadService::DeviceRemoved(IOHIDDeviceRef device)
 {
-  GamepadPlatformService* service =
+  RefPtr<GamepadPlatformService> service =
     GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
+  if (!service) {
+    return;
+  }
   for (size_t i = 0; i < mGamepads.size(); i++) {
     if (mGamepads[i] == device) {
       service->RemoveGamepad(mGamepads[i].mSuperIndex);
       mGamepads[i].clear();
       return;
     }
   }
 }
@@ -338,27 +343,31 @@ UnpackDpad(int dpad_value, int min, int 
   if (value > 0 && value < 4) {
     buttons[kRight] = true;
   }
 }
 
 void
 DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
 {
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return;
+  }
+
   uint32_t value_length = IOHIDValueGetLength(value);
   if (value_length > 4) {
     // Workaround for bizarre issue with PS3 controllers that try to return
     // massive (30+ byte) values and crash IOHIDValueGetIntegerValue
     return;
   }
   IOHIDElementRef element = IOHIDValueGetElement(value);
   IOHIDDeviceRef device = IOHIDElementGetDevice(element);
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
+
   for (unsigned i = 0; i < mGamepads.size(); i++) {
     Gamepad &gamepad = mGamepads[i];
     if (gamepad == device) {
       if (gamepad.isDpad(element)) {
         const dpad_buttons& oldState = gamepad.getDpadState();
         dpad_buttons newState = { false, false, false, false };
         UnpackDpad(IOHIDValueGetIntegerValue(value),
                    IOHIDElementGetLogicalMin(element),
--- a/dom/gamepad/ipc/GamepadEventChannelParent.cpp
+++ b/dom/gamepad/ipc/GamepadEventChannelParent.cpp
@@ -37,17 +37,17 @@ class SendGamepadUpdateRunnable final : 
   }
 };
 
 } // namespace
 
 GamepadEventChannelParent::GamepadEventChannelParent()
   : mHasGamepadListener(false)
 {
-  GamepadPlatformService* service =
+  RefPtr<GamepadPlatformService> service =
     GamepadPlatformService::GetParentService();
   MOZ_ASSERT(service);
   service->AddChannelParent(this);
   mBackgroundThread = NS_GetCurrentThread();
 }
 
 bool
 GamepadEventChannelParent::RecvGamepadListenerAdded()
@@ -60,34 +60,34 @@ GamepadEventChannelParent::RecvGamepadLi
 }
 
 bool
 GamepadEventChannelParent::RecvGamepadListenerRemoved()
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(mHasGamepadListener);
   mHasGamepadListener = false;
-  GamepadPlatformService* service =
+  RefPtr<GamepadPlatformService> service =
     GamepadPlatformService::GetParentService();
   MOZ_ASSERT(service);
   service->RemoveChannelParent(this);
   Unused << Send__delete__(this);
   return true;
 }
 
 void
 GamepadEventChannelParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsOnBackgroundThread();
 
   // It may be called because IPDL child side crashed, we'll
   // not receive RecvGamepadListenerRemoved in that case
   if (mHasGamepadListener) {
     mHasGamepadListener = false;
-    GamepadPlatformService* service =
+    RefPtr<GamepadPlatformService> service =
       GamepadPlatformService::GetParentService();
     MOZ_ASSERT(service);
     service->RemoveChannelParent(this);
   }
   MaybeStopGamepadMonitoring();
 }
 
 void
--- a/dom/gamepad/ipc/GamepadTestChannelParent.cpp
+++ b/dom/gamepad/ipc/GamepadTestChannelParent.cpp
@@ -10,17 +10,17 @@
 namespace mozilla {
 namespace dom {
 
 bool
 GamepadTestChannelParent::RecvGamepadTestEvent(const uint32_t& aID,
                                                const GamepadChangeEvent& aEvent)
 {
   mozilla::ipc::AssertIsOnBackgroundThread();
-  GamepadPlatformService*  service =
+  RefPtr<GamepadPlatformService>  service =
     GamepadPlatformService::GetParentService();
   MOZ_ASSERT(service);
   if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) {
     const GamepadAdded& a = aEvent.get_GamepadAdded();
     nsCString gamepadID;
     LossyCopyUTF16toASCII(a.id(), gamepadID);
     uint32_t index = service->AddGamepad(gamepadID.get(),
                                          (GamepadMappingType)a.mapping(),
--- a/dom/gamepad/linux/LinuxGamepad.cpp
+++ b/dom/gamepad/linux/LinuxGamepad.cpp
@@ -81,16 +81,22 @@ private:
 };
 
 // singleton instance
 LinuxGamepadService* gService = nullptr;
 
 void
 LinuxGamepadService::AddDevice(struct udev_device* dev)
 {
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return;
+  }
+
   const char* devpath = mUdev.udev_device_get_devnode(dev);
   if (!devpath) {
     return;
   }
 
   // Ensure that this device hasn't already been added.
   for (unsigned int i = 0; i < mGamepads.Length(); i++) {
     if (strcmp(mGamepads[i].devpath, devpath) == 0) {
@@ -129,19 +135,16 @@ LinuxGamepadService::AddDevice(struct ud
   }
   snprintf(gamepad.idstring, sizeof(gamepad.idstring),
            "%s-%s-%s",
            vendor_id ? vendor_id : "unknown",
            model_id ? model_id : "unknown",
            name);
 
   char numAxes = 0, numButtons = 0;
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
   ioctl(fd, JSIOCGAXES, &numAxes);
   gamepad.numAxes = numAxes;
   ioctl(fd, JSIOCGBUTTONS, &numButtons);
   gamepad.numButtons = numButtons;
 
   gamepad.index = service->AddGamepad(gamepad.idstring,
                                       mozilla::dom::GamepadMappingType::_empty,
                                       gamepad.numButtons,
@@ -155,23 +158,27 @@ LinuxGamepadService::AddDevice(struct ud
   g_io_channel_unref(channel);
 
   mGamepads.AppendElement(gamepad);
 }
 
 void
 LinuxGamepadService::RemoveDevice(struct udev_device* dev)
 {
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return;
+  }
+
   const char* devpath = mUdev.udev_device_get_devnode(dev);
   if (!devpath) {
     return;
   }
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
+
   for (unsigned int i = 0; i < mGamepads.Length(); i++) {
     if (strcmp(mGamepads[i].devpath, devpath) == 0) {
       g_source_remove(mGamepads[i].source_id);
       service->RemoveGamepad(mGamepads[i].index);
       mGamepads.RemoveElementAt(i);
       break;
     }
   }
@@ -295,20 +302,22 @@ LinuxGamepadService::ReadUdevChange()
 }
 
 // static
 gboolean
 LinuxGamepadService::OnGamepadData(GIOChannel* source,
                                    GIOCondition condition,
                                    gpointer data)
 {
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return TRUE;
+  }
   int index = GPOINTER_TO_INT(data);
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
   //TODO: remove gamepad?
   if (condition & G_IO_ERR || condition & G_IO_HUP)
     return FALSE;
 
   while (true) {
     struct js_event event;
     gsize count;
     GError* err = nullptr;
--- a/dom/gamepad/windows/WindowsGamepad.cpp
+++ b/dom/gamepad/windows/WindowsGamepad.cpp
@@ -426,31 +426,34 @@ WindowsGamepadService::HaveXInputGamepad
 }
 
 bool
 WindowsGamepadService::ScanForXInputDevices()
 {
   MOZ_ASSERT(mXInput, "XInput should be present!");
 
   bool found = false;
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return found;
+  }
+
   for (int i = 0; i < XUSER_MAX_COUNT; i++) {
     XINPUT_STATE state = {};
     if (mXInput.mXInputGetState(i, &state) != ERROR_SUCCESS) {
       continue;
     }
     found = true;
     // See if this device is already present in our list.
     if (HaveXInputGamepad(i)) {
       continue;
     }
 
     // Not already present, add it.
-    GamepadPlatformService* service =
-      GamepadPlatformService::GetParentService();
-    MOZ_ASSERT(service);
     Gamepad gamepad = {};
     gamepad.type = kXInputGamepad;
     gamepad.present = true;
     gamepad.state = state;
     gamepad.userIndex = i;
     gamepad.numButtons = kStandardGamepadButtons;
     gamepad.numAxes = kStandardGamepadAxes;
     gamepad.id = service->AddGamepad("xinput",
@@ -461,16 +464,22 @@ WindowsGamepadService::ScanForXInputDevi
   }
 
   return found;
 }
 
 void
 WindowsGamepadService::ScanForDevices()
 {
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return;
+  }
+
   for (int i = mGamepads.Length() - 1; i >= 0; i--) {
     mGamepads[i].present = false;
   }
 
   if (mHID) {
     ScanForRawInputDevices();
   }
   if (mXInput) {
@@ -481,19 +490,16 @@ WindowsGamepadService::ScanForDevices()
                                          kXInputPollInterval,
                                          nsITimer::TYPE_ONE_SHOT);
     } else {
       mIsXInputMonitoring = false;
     }
   }
 
   // Look for devices that are no longer present and remove them.
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
   for (int i = mGamepads.Length() - 1; i >= 0; i--) {
     if (!mGamepads[i].present) {
       service->RemoveGamepad(mGamepads[i].id);
       mGamepads.RemoveElementAt(i);
     }
   }
 }
 
@@ -511,19 +517,21 @@ WindowsGamepadService::PollXInput()
         && state.dwPacketNumber != mGamepads[i].state.dwPacketNumber) {
         CheckXInputChanges(mGamepads[i], state);
     }
   }
 }
 
 void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad,
                                                XINPUT_STATE& state) {
-  GamepadPlatformService* service =
+  RefPtr<GamepadPlatformService> service =
     GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
+  if (!service) {
+    return;
+  }
   // Handle digital buttons first
   for (size_t b = 0; b < kNumMappings; b++) {
     if (state.Gamepad.wButtons & kXIButtonMap[b].button &&
         !(gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button)) {
       // Button pressed
       service->NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, true);
     } else if (!(state.Gamepad.wButtons & kXIButtonMap[b].button) &&
                gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button) {
@@ -581,16 +589,22 @@ public:
     }
     return c1.UsagePage < c2.UsagePage;
   }
 };
 
 bool
 WindowsGamepadService::GetRawGamepad(HANDLE handle)
 {
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (!service) {
+    return true;
+  }
+
   if (!mHID) {
     return false;
   }
 
   for (unsigned i = 0; i < mGamepads.Length(); i++) {
     if (mGamepads[i].type == kRawInputGamepad && mGamepads[i].handle == handle) {
       mGamepads[i].present = true;
       return true;
@@ -717,35 +731,37 @@ WindowsGamepadService::GetRawGamepad(HAN
     if (i >= kMaxAxes) {
       break;
     }
     gamepad.axes[i].caps = axes[i];
   }
   gamepad.type = kRawInputGamepad;
   gamepad.handle = handle;
   gamepad.present = true;
-
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
   gamepad.id = service->AddGamepad(gamepad_id,
                                    GamepadMappingType::_empty,
                                    gamepad.numButtons,
                                    gamepad.numAxes);
   mGamepads.AppendElement(gamepad);
   return true;
 }
 
 bool
 WindowsGamepadService::HandleRawInput(HRAWINPUT handle)
 {
   if (!mHID) {
     return false;
   }
 
+  RefPtr<GamepadPlatformService> service =
+    GamepadPlatformService::GetParentService();
+  if (service) {
+    return true;
+  }
+
   // First, get data from the handle
   UINT size;
   GetRawInputData(handle, RID_INPUT, nullptr, &size, sizeof(RAWINPUTHEADER));
   nsTArray<uint8_t> data(size);
   data.SetLength(size);
   if (GetRawInputData(handle, RID_INPUT, data.Elements(), &size,
                       sizeof(RAWINPUTHEADER)) == kRawInputError) {
     return false;
@@ -768,19 +784,16 @@ WindowsGamepadService::HandleRawInput(HR
   nsTArray<uint8_t> parsedbytes;
   if (!GetPreparsedData(raw->header.hDevice, parsedbytes)) {
     return false;
   }
   PHIDP_PREPARSED_DATA parsed =
     reinterpret_cast<PHIDP_PREPARSED_DATA>(parsedbytes.Elements());
 
   // Get all the pressed buttons.
-  GamepadPlatformService* service =
-    GamepadPlatformService::GetParentService();
-  MOZ_ASSERT(service);
   nsTArray<USAGE> usages(gamepad->numButtons);
   usages.SetLength(gamepad->numButtons);
   ULONG usageLength = gamepad->numButtons;
   if (mHID.mHidP_GetUsages(HidP_Input, kButtonUsagePage, 0, usages.Elements(),
                      &usageLength, parsed, (PCHAR)raw->data.hid.bRawData,
                      raw->data.hid.dwSizeHid) != HIDP_STATUS_SUCCESS) {
     return false;
   }
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -929,19 +929,21 @@ nsAppShell::LegacyGeckoEvent::Run()
         } else {
             Telemetry::Accumulate(NS_ConvertUTF16toUTF8(curEvent->Characters()).get(),
                                   curEvent->Count());
         }
         break;
 
     case AndroidGeckoEvent::GAMEPAD_ADDREMOVE: {
 #ifdef MOZ_GAMEPAD
-            GamepadPlatformService* service;
+            RefPtr<GamepadPlatformService> service;
             service = GamepadPlatformService::GetParentService();
-            MOZ_ASSERT(service);
+            if (!service) {
+              break;
+            }
             if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_ADDED) {
               int svc_id = service->AddGamepad("android",
                                                dom::GamepadMappingType::Standard,
                                                dom::kStandardGamepadButtons,
                                                dom::kStandardGamepadAxes);
               widget::GeckoAppShell::GamepadAdded(curEvent->ID(),
                                                   svc_id);
             } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_REMOVED) {
@@ -949,19 +951,21 @@ nsAppShell::LegacyGeckoEvent::Run()
             }
 #endif
         break;
     }
 
     case AndroidGeckoEvent::GAMEPAD_DATA: {
 #ifdef MOZ_GAMEPAD
             int id = curEvent->ID();
-            GamepadPlatformService* service;
+            RefPtr<GamepadPlatformService> service;
             service = GamepadPlatformService::GetParentService();
-            MOZ_ASSERT(service);
+            if (!service) {
+              break;
+            }
             if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_BUTTON) {
               service->NewButtonEvent(id, curEvent->GamepadButton(),
                                       curEvent->GamepadButtonPressed(),
                                       curEvent->GamepadButtonValue());
             } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_AXES) {
                 int valid = curEvent->Flags();
                 const nsTArray<float>& values = curEvent->GamepadValues();
                 for (unsigned i = 0; i < values.Length(); i++) {