Bug 1401678 - Proxy nsISound::beep() and nsISound::play() calls from the content process to the parent process and beep away there. r?bkelly draft
authorMike de Boer <mdeboer@mozilla.com>
Tue, 16 Jan 2018 13:24:51 +0100
changeset 720869 ad2a31cd1cf9cb9c02cc3a97216aa5e2bc51ba6e
parent 720380 b7d66e4e60ef177ec9ae687daa29443ae4a2acfc
child 746180 2dd039c26246faeefd561c88d23c0948cb3bcf56
push id95673
push usermdeboer@mozilla.com
push dateTue, 16 Jan 2018 12:25:25 +0000
reviewersbkelly
bugs1401678
milestone59.0a1
Bug 1401678 - Proxy nsISound::beep() and nsISound::play() calls from the content process to the parent process and beep away there. r?bkelly MozReview-Commit-ID: J7NwDeVYvQw
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
widget/moz.build
widget/nsContentProcessWidgetFactory.cpp
widget/nsSoundProxy.cpp
widget/nsSoundProxy.h
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -137,20 +137,22 @@
 #include "nsIMutable.h"
 #include "nsIObserverService.h"
 #include "nsIParentChannel.h"
 #include "nsIPresShell.h"
 #include "nsIRemoteWindowContext.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISiteSecurityService.h"
+#include "nsISound.h"
 #include "nsISpellChecker.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITimer.h"
 #include "nsIURIFixup.h"
+#include "nsIURL.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIXULWindow.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIWindowWatcher.h"
 #include "nsPIWindowWatcher.h"
 #include "nsThread.h"
 #include "nsWindowWatcher.h"
 #include "nsIXULRuntime.h"
@@ -2666,16 +2668,64 @@ ContentParent::RecvClipboardHasType(nsTA
   clipboard->HasDataMatchingFlavors(typesChrs, aTypes.Length(),
                                     aWhichClipboard, aHasType);
 
   delete [] typesChrs;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+ContentParent::RecvPlaySound(const URIParams& aURI)
+{
+  nsCOMPtr<nsIURI> soundURI = DeserializeURI(aURI);
+  bool isChrome = false;
+  // If the check here fails, it can only mean that this message was spoofed.
+  if (!soundURI || NS_FAILED(soundURI->SchemeIs("chrome", &isChrome)) || !isChrome) {
+    KillHard("PlaySound only accepts a valid chrome URI.");
+    return IPC_OK();
+  }
+  nsCOMPtr<nsIURL> soundURL(do_QueryInterface(soundURI));
+  if (!soundURL) {
+    return IPC_OK();
+  }
+
+  nsresult rv;
+  nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
+  NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+  sound->Play(soundURL);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ContentParent::RecvBeep()
+{
+  nsresult rv;
+  nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
+  NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+  sound->Beep();
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ContentParent::RecvPlayEventSound(const uint32_t& aEventId)
+{
+  nsresult rv;
+  nsCOMPtr<nsISound> sound(do_GetService(NS_SOUND_CID, &rv));
+  NS_ENSURE_SUCCESS(rv, IPC_OK());
+
+  sound->PlayEventSound(aEventId);
+
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 ContentParent::RecvGetSystemColors(const uint32_t& colorsCount,
                                    InfallibleTArray<uint32_t>* colors)
 {
 #ifdef MOZ_WIDGET_ANDROID
   NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
   if (AndroidBridge::Bridge() == nullptr) {
     // Do not fail - the colors won't be right, but it's not critical
     return IPC_OK();
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -985,16 +985,20 @@ private:
                                                    IPCDataTransfer* aDataTransfer) override;
 
   virtual mozilla::ipc::IPCResult RecvEmptyClipboard(const int32_t& aWhichClipboard) override;
 
   virtual mozilla::ipc::IPCResult RecvClipboardHasType(nsTArray<nsCString>&& aTypes,
                                                        const int32_t& aWhichClipboard,
                                                        bool* aHasType) override;
 
+  virtual mozilla::ipc::IPCResult RecvPlaySound(const URIParams& aURI) override;
+  virtual mozilla::ipc::IPCResult RecvBeep() override;
+  virtual mozilla::ipc::IPCResult RecvPlayEventSound(const uint32_t& aEventId) override;
+
   virtual mozilla::ipc::IPCResult RecvGetSystemColors(const uint32_t& colorsCount,
                                                       InfallibleTArray<uint32_t>* colors) override;
 
   virtual mozilla::ipc::IPCResult RecvGetIconForExtension(const nsCString& aFileExt,
                                                           const uint32_t& aIconSize,
                                                           InfallibleTArray<uint8_t>* bits) override;
 
   virtual mozilla::ipc::IPCResult RecvGetShowPasswordSetting(bool* showPassword) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -843,16 +843,22 @@ parent:
 
     // Clears the clipboard.
     async EmptyClipboard(int32_t aWhichClipboard);
 
     // Returns true if data of one of the specified types is on the clipboard.
     sync ClipboardHasType(nsCString[] aTypes, int32_t aWhichClipboard)
         returns (bool hasType);
 
+    // 'Play', 'Beep' and 'PlayEventSound' are the only nsISound methods used in
+    // the content process.
+    async PlaySound(URIParams aURL) compress;
+    async Beep() compress;
+    async PlayEventSound(uint32_t aEventId) compress;
+
     sync GetSystemColors(uint32_t colorsCount)
         returns (uint32_t[] colors);
 
     sync GetIconForExtension(nsCString aFileExt, uint32_t aIconSize)
         returns (uint8_t[] bits);
 
     sync GetShowPasswordSetting()
         returns (bool showPassword);
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -185,16 +185,17 @@ UNIFIED_SOURCES += [
     'nsContentProcessWidgetFactory.cpp',
     'nsDragServiceProxy.cpp',
     'nsFilePickerProxy.cpp',
     'nsHTMLFormatConverter.cpp',
     'nsIdleService.cpp',
     'nsIWidgetListener.cpp',
     'nsPrimitiveHelpers.cpp',
     'nsPrintSettingsImpl.cpp',
+    'nsSoundProxy.cpp',
     'nsTransferable.cpp',
     'nsXPLookAndFeel.cpp',
     'PuppetBidiKeyboard.cpp',
     'PuppetWidget.cpp',
     'Screen.cpp',
     'ScreenManager.cpp',
     'SharedWidgetUtils.cpp',
     'TextEventDispatcher.cpp',
--- a/widget/nsContentProcessWidgetFactory.cpp
+++ b/widget/nsContentProcessWidgetFactory.cpp
@@ -6,57 +6,63 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ModuleUtils.h"
 #include "nsWidgetsCID.h"
 #include "nsClipboardProxy.h"
 #include "nsColorPickerProxy.h"
 #include "nsDragServiceProxy.h"
 #include "nsFilePickerProxy.h"
+#include "nsSoundProxy.h"
 #include "mozilla/widget/PuppetBidiKeyboard.h"
 #include "mozilla/widget/ScreenManager.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsColorPickerProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragServiceProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePickerProxy)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsSoundProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PuppetBidiKeyboard)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ScreenManager, ScreenManager::GetAddRefedSingleton)
 
 NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID);
 NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID);
 NS_DEFINE_NAMED_CID(NS_DRAGSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
+NS_DEFINE_NAMED_CID(NS_SOUND_CID);
 NS_DEFINE_NAMED_CID(PUPPETBIDIKEYBOARD_CID);
 NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID);
 
 static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
     { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_COLORPICKER_CID, false, nullptr, nsColorPickerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_DRAGSERVICE_CID, false, nullptr, nsDragServiceProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_FILEPICKER_CID, false, nullptr, nsFilePickerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
+    { &kNS_SOUND_CID, false, nullptr, nsSoundProxyConstructor,
+      Module::CONTENT_PROCESS_ONLY },
     { &kPUPPETBIDIKEYBOARD_CID, false, NULL, PuppetBidiKeyboardConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_SCREENMANAGER_CID, false, nullptr, ScreenManagerConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
     { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, Module::CONTENT_PROCESS_ONLY },
+    { "@mozilla.org/sound;1", &kNS_SOUND_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/widget/dragservice;1", &kNS_DRAGSERVICE_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/widget/bidikeyboard;1", &kPUPPETBIDIKEYBOARD_CID,
       Module::CONTENT_PROCESS_ONLY },
     { nullptr }
 };
 
 static const mozilla::Module kWidgetModule = {
     mozilla::Module::kVersion,
new file mode 100644
--- /dev/null
+++ b/widget/nsSoundProxy.cpp
@@ -0,0 +1,66 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/ipc/URIUtils.h"
+#include "nsIURL.h"
+#include "nsIURI.h"
+#include "nsSoundProxy.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS(nsSoundProxy, nsISound)
+
+NS_IMETHODIMP
+nsSoundProxy::Play(nsIURL *aURL)
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
+
+  nsCOMPtr<nsIURI> soundURI(do_QueryInterface(aURL));
+  bool isChrome = false;
+  // Only allow playing a chrome:// URL from the content process.
+  if (!soundURI || NS_FAILED(soundURI->SchemeIs("chrome", &isChrome)) || !isChrome) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mozilla::ipc::URIParams soundParams;
+  mozilla::ipc::SerializeURI(soundURI, soundParams);
+  ContentChild::GetSingleton()->SendPlaySound(soundParams);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSoundProxy::PlaySystemSound(const nsAString &aSoundAlias)
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
+  MOZ_ASSERT(false, "PlaySystemSound is unimplemented.");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsSoundProxy::Beep()
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
+
+  ContentChild::GetSingleton()->SendBeep();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsSoundProxy::Init()
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
+  MOZ_DIAGNOSTIC_ASSERT(false, "Only called by XUL in the parent process.");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsSoundProxy::PlayEventSound(uint32_t aEventId)
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Content);
+
+  ContentChild::GetSingleton()->SendPlayEventSound(aEventId);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/widget/nsSoundProxy.h
@@ -0,0 +1,23 @@
+/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NS_SOUND_PROXY_H
+#define NS_SOUND_PROXY_H
+
+#include "nsISound.h"
+
+class nsSoundProxy final : public nsISound
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISOUND
+
+  nsSoundProxy() = default;
+
+private:
+  ~nsSoundProxy() = default;
+};
+
+#endif