LCOV - code coverage report
Current view: top level - dom/gamepad - GamepadPlatformService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 117 0.9 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/GamepadPlatformService.h"
       8             : 
       9             : #include "mozilla/dom/GamepadEventChannelParent.h"
      10             : #include "mozilla/ipc/BackgroundParent.h"
      11             : #include "mozilla/Mutex.h"
      12             : #include "mozilla/Unused.h"
      13             : 
      14             : #include "nsCOMPtr.h"
      15             : #include "nsHashKeys.h"
      16             : #include "nsIThread.h"
      17             : 
      18             : using namespace mozilla::ipc;
      19             : 
      20             : namespace mozilla {
      21             : namespace dom {
      22             : 
      23             : namespace {
      24             : 
      25             : // This is the singleton instance of GamepadPlatformService, can be called
      26             : // by both background and monitor thread.
      27           3 : StaticRefPtr<GamepadPlatformService> gGamepadPlatformServiceSingleton;
      28             : 
      29             : } //namepsace
      30             : 
      31           0 : GamepadPlatformService::GamepadPlatformService()
      32             :   : mGamepadIndex(0),
      33           0 :     mMutex("mozilla::dom::GamepadPlatformService")
      34           0 : {}
      35             : 
      36           0 : GamepadPlatformService::~GamepadPlatformService()
      37             : {
      38           0 :   Cleanup();
      39           0 : }
      40             : 
      41             : // static
      42             : already_AddRefed<GamepadPlatformService>
      43           0 : GamepadPlatformService::GetParentService()
      44             : {
      45             :   //GamepadPlatformService can only be accessed in parent process
      46           0 :   MOZ_ASSERT(XRE_IsParentProcess());
      47           0 :   if (!gGamepadPlatformServiceSingleton) {
      48             :     // Only Background Thread can create new GamepadPlatformService instance.
      49           0 :     if (IsOnBackgroundThread()) {
      50           0 :       gGamepadPlatformServiceSingleton = new GamepadPlatformService();
      51             :     } else {
      52           0 :       return nullptr;
      53             :     }
      54             :   }
      55           0 :   RefPtr<GamepadPlatformService> service(gGamepadPlatformServiceSingleton);
      56           0 :   return service.forget();
      57             : }
      58             : 
      59             : template<class T>
      60             : void
      61           0 : GamepadPlatformService::NotifyGamepadChange(const T& aInfo)
      62             : {
      63             :   // This method is called by monitor populated in
      64             :   // platform-dependent backends
      65           0 :   MOZ_ASSERT(XRE_IsParentProcess());
      66           0 :   MOZ_ASSERT(!NS_IsMainThread());
      67             : 
      68           0 :   GamepadChangeEvent e(aInfo);
      69             : 
      70             :   // mChannelParents may be accessed by background thread in the
      71             :   // same time, we use mutex to prevent possible race condtion
      72           0 :   MutexAutoLock autoLock(mMutex);
      73             : 
      74             :   // Buffer all events if we have no Channel to dispatch, which
      75             :   // may happen when performing Mochitest.
      76           0 :   if (mChannelParents.IsEmpty()) {
      77           0 :     mPendingEvents.AppendElement(e);
      78           0 :     return;
      79             :   }
      80             : 
      81           0 :   for(uint32_t i = 0; i < mChannelParents.Length(); ++i) {
      82           0 :     mChannelParents[i]->DispatchUpdateEvent(e);
      83             :   }
      84             : }
      85             : 
      86             : uint32_t
      87           0 : GamepadPlatformService::AddGamepad(const char* aID,
      88             :                                    GamepadMappingType aMapping,
      89             :                                    GamepadHand aHand,
      90             :                                    uint32_t aNumButtons, uint32_t aNumAxes,
      91             :                                    uint32_t aHaptics)
      92             : {
      93             :   // This method is called by monitor thread populated in
      94             :   // platform-dependent backends
      95           0 :   MOZ_ASSERT(XRE_IsParentProcess());
      96           0 :   MOZ_ASSERT(!NS_IsMainThread());
      97             : 
      98           0 :   uint32_t index = ++mGamepadIndex;
      99           0 :   GamepadAdded a(NS_ConvertUTF8toUTF16(nsDependentCString(aID)), index,
     100             :                  aMapping, aHand, GamepadServiceType::Standard,
     101           0 :                  aNumButtons, aNumAxes, aHaptics);
     102             : 
     103           0 :   NotifyGamepadChange<GamepadAdded>(a);
     104           0 :   return index;
     105             : }
     106             : 
     107             : void
     108           0 : GamepadPlatformService::RemoveGamepad(uint32_t aIndex)
     109             : {
     110             :   // This method is called by monitor thread populated in
     111             :   // platform-dependent backends
     112           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     113           0 :   MOZ_ASSERT(!NS_IsMainThread());
     114           0 :   GamepadRemoved a(aIndex, GamepadServiceType::Standard);
     115           0 :   NotifyGamepadChange<GamepadRemoved>(a);
     116           0 : }
     117             : 
     118             : void
     119           0 : GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
     120             :                                        bool aPressed, bool aTouched,
     121             :                                        double aValue)
     122             : {
     123             :   // This method is called by monitor thread populated in
     124             :   // platform-dependent backends
     125           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     126           0 :   MOZ_ASSERT(!NS_IsMainThread());
     127             :   GamepadButtonInformation a(aIndex, GamepadServiceType::Standard,
     128           0 :                              aButton, aValue, aPressed, aTouched);
     129           0 :   NotifyGamepadChange<GamepadButtonInformation>(a);
     130           0 : }
     131             : 
     132             : void
     133           0 : GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
     134             :                                        bool aPressed, bool aTouched)
     135             : {
     136             :   // This method is called by monitor thread populated in
     137             :   // platform-dependent backends
     138           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     139           0 :   MOZ_ASSERT(!NS_IsMainThread());
     140             :   // When only a digital button is available the value will be synthesized.
     141           0 :   NewButtonEvent(aIndex, aButton, aPressed, aTouched, aPressed ? 1.0L : 0.0L);
     142           0 : }
     143             : 
     144             : void
     145           0 : GamepadPlatformService::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
     146             :                                        bool aPressed)
     147             : {
     148             :   // This method is called by monitor thread populated in
     149             :   // platform-dependent backends
     150           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     151           0 :   MOZ_ASSERT(!NS_IsMainThread());
     152             :   // When only a digital button is available the value will be synthesized.
     153           0 :   NewButtonEvent(aIndex, aButton, aPressed, aPressed, aPressed ? 1.0L : 0.0L);
     154           0 : }
     155             : 
     156             : void
     157           0 : GamepadPlatformService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis,
     158             :                                          double aValue)
     159             : {
     160             :   // This method is called by monitor thread populated in
     161             :   // platform-dependent backends
     162           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     163           0 :   MOZ_ASSERT(!NS_IsMainThread());
     164             :   GamepadAxisInformation a(aIndex, GamepadServiceType::Standard,
     165           0 :                            aAxis, aValue);
     166           0 :   NotifyGamepadChange<GamepadAxisInformation>(a);
     167           0 : }
     168             : 
     169             : void
     170           0 : GamepadPlatformService::NewPoseEvent(uint32_t aIndex,
     171             :                                      const GamepadPoseState& aPose)
     172             : {
     173             :   // This method is called by monitor thread populated in
     174             :   // platform-dependent backends
     175           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     176           0 :   MOZ_ASSERT(!NS_IsMainThread());
     177             :   GamepadPoseInformation a(aIndex, GamepadServiceType::Standard,
     178           0 :                            aPose);
     179           0 :   NotifyGamepadChange<GamepadPoseInformation>(a);
     180           0 : }
     181             : 
     182             : void
     183           0 : GamepadPlatformService::ResetGamepadIndexes()
     184             : {
     185             :   // This method is called by monitor thread populated in
     186             :   // platform-dependent backends
     187           0 :   MOZ_ASSERT(XRE_IsParentProcess());
     188           0 :   MOZ_ASSERT(!NS_IsMainThread());
     189           0 :   mGamepadIndex = 0;
     190           0 : }
     191             : 
     192             : void
     193           0 : GamepadPlatformService::AddChannelParent(GamepadEventChannelParent* aParent)
     194             : {
     195             :   // mChannelParents can only be modified once GamepadEventChannelParent
     196             :   // is created or removed in Background thread
     197           0 :   AssertIsOnBackgroundThread();
     198           0 :   MOZ_ASSERT(aParent);
     199           0 :   MOZ_ASSERT(!mChannelParents.Contains(aParent));
     200             : 
     201             :   // We use mutex here to prevent race condition with monitor thread
     202           0 :   MutexAutoLock autoLock(mMutex);
     203           0 :   mChannelParents.AppendElement(aParent);
     204           0 :   FlushPendingEvents();
     205           0 : }
     206             : 
     207             : void
     208           0 : GamepadPlatformService::FlushPendingEvents()
     209             : {
     210           0 :   AssertIsOnBackgroundThread();
     211           0 :   MOZ_ASSERT(!mChannelParents.IsEmpty());
     212             : 
     213           0 :   if (mPendingEvents.IsEmpty()) {
     214           0 :     return;
     215             :   }
     216             : 
     217             :   // NOTE: This method must be called with mMutex held because it accesses
     218             :   // mChannelParents.
     219           0 :   for (uint32_t i=0; i<mChannelParents.Length(); ++i) {
     220           0 :     for (uint32_t j=0; j<mPendingEvents.Length();++j) {
     221           0 :       mChannelParents[i]->DispatchUpdateEvent(mPendingEvents[j]);
     222             :     }
     223             :   }
     224           0 :   mPendingEvents.Clear();
     225             : }
     226             : 
     227             : void
     228           0 : GamepadPlatformService::RemoveChannelParent(GamepadEventChannelParent* aParent)
     229             : {
     230             :   // mChannelParents can only be modified once GamepadEventChannelParent
     231             :   // is created or removed in Background thread
     232           0 :   AssertIsOnBackgroundThread();
     233           0 :   MOZ_ASSERT(aParent);
     234           0 :   MOZ_ASSERT(mChannelParents.Contains(aParent));
     235             : 
     236             :   // We use mutex here to prevent race condition with monitor thread
     237           0 :   MutexAutoLock autoLock(mMutex);
     238           0 :   mChannelParents.RemoveElement(aParent);
     239           0 : }
     240             : 
     241             : bool
     242           0 : GamepadPlatformService::HasGamepadListeners()
     243             : {
     244             :   // mChannelParents may be accessed by background thread in the
     245             :   // same time, we use mutex to prevent possible race condtion
     246           0 :   AssertIsOnBackgroundThread();
     247             : 
     248             :   // We use mutex here to prevent race condition with monitor thread
     249           0 :   MutexAutoLock autoLock(mMutex);
     250           0 :   for (uint32_t i = 0; i < mChannelParents.Length(); i++) {
     251           0 :     if(mChannelParents[i]->HasGamepadListener()) {
     252           0 :       return true;
     253             :     }
     254             :   }
     255           0 :   return false;
     256             : }
     257             : 
     258             : void
     259           0 : GamepadPlatformService::MaybeShutdown()
     260             : {
     261             :   // This method is invoked in MaybeStopGamepadMonitoring when
     262             :   // an IPDL channel is going to be destroyed
     263           0 :   AssertIsOnBackgroundThread();
     264             : 
     265             :   // We have to release gGamepadPlatformServiceSingleton ouside
     266             :   // the mutex as well as making upcoming GetParentService() call
     267             :   // recreate new singleton, so we use this RefPtr to temporarily
     268             :   // hold the reference, postponing the release process until this
     269             :   // method ends.
     270           0 :   RefPtr<GamepadPlatformService> kungFuDeathGrip;
     271             : 
     272             :   bool isChannelParentEmpty;
     273             :   {
     274           0 :     MutexAutoLock autoLock(mMutex);
     275           0 :     isChannelParentEmpty = mChannelParents.IsEmpty();
     276           0 :     if(isChannelParentEmpty) {
     277           0 :       kungFuDeathGrip = gGamepadPlatformServiceSingleton;
     278           0 :       gGamepadPlatformServiceSingleton = nullptr;
     279             :     }
     280             :   }
     281           0 : }
     282             : 
     283             : void
     284           0 : GamepadPlatformService::Cleanup()
     285             : {
     286             :   // This method is called when GamepadPlatformService is
     287             :   // successfully distructed in background thread
     288           0 :   AssertIsOnBackgroundThread();
     289             : 
     290           0 :   MutexAutoLock autoLock(mMutex);
     291           0 :   mChannelParents.Clear();
     292           0 : }
     293             : 
     294             : } // namespace dom
     295             : } // namespace mozilla

Generated by: LCOV version 1.13